summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Jamfile.jam2
-rw-r--r--lib/dbConn.h14
-rw-r--r--lib/dbTypes.h31
-rw-r--r--lib/helpers.h19
-rw-r--r--lib/input/mysqlConn.cpp78
-rw-r--r--lib/input/mysqlConn.h8
-rw-r--r--lib/mysql_types.h40
-rw-r--r--lib/output/pq/pqConn.cpp70
-rw-r--r--lib/output/pq/pqConn.h8
-rw-r--r--lib/row.cpp1
-rw-r--r--lib/row.h4
-rw-r--r--lib/streamSupport.cpp10
-rw-r--r--lib/streamSupport.h12
13 files changed, 258 insertions, 39 deletions
diff --git a/lib/Jamfile.jam b/lib/Jamfile.jam
index 05699a8..c54dabc 100644
--- a/lib/Jamfile.jam
+++ b/lib/Jamfile.jam
@@ -4,7 +4,9 @@ lib mygrate :
<link>static
<include>.
<use>..//libmariadb
+ <use>..//libpq
: :
<include>.
<library>..//libmariadb
+ <library>..//libpq
;
diff --git a/lib/dbConn.h b/lib/dbConn.h
new file mode 100644
index 0000000..26b9a64
--- /dev/null
+++ b/lib/dbConn.h
@@ -0,0 +1,14 @@
+#ifndef MYGRATE_DBCONN_H
+#define MYGRATE_DBCONN_H
+
+#include <dbTypes.h>
+#include <initializer_list>
+
+namespace MyGrate {
+ class DbConn {
+ virtual void query(const char * const) = 0;
+ virtual void query(const char * const, const std::initializer_list<DbValue> &) = 0;
+ };
+}
+
+#endif
diff --git a/lib/dbTypes.h b/lib/dbTypes.h
new file mode 100644
index 0000000..ba0cd70
--- /dev/null
+++ b/lib/dbTypes.h
@@ -0,0 +1,31 @@
+#ifndef MYGRATE_DBTYPES_H
+#define MYGRATE_DBTYPES_H
+
+#include "bitset.h"
+#include <cstdint>
+#include <span>
+#include <string_view>
+#include <variant>
+
+struct timespec;
+
+namespace MyGrate {
+ struct Date {
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ };
+ struct Time {
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ };
+ struct DateTime : public Date, public Time {
+ };
+ using Blob = std::span<const std::byte>;
+
+ using DbValue = std::variant<std::nullptr_t, double, float, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
+ int64_t, uint64_t, timespec, Date, Time, DateTime, std::string_view, BitSet, Blob>;
+}
+
+#endif
diff --git a/lib/helpers.h b/lib/helpers.h
index 3a94ead..a8a630e 100644
--- a/lib/helpers.h
+++ b/lib/helpers.h
@@ -3,6 +3,7 @@
#include <concepts>
#include <cstdint>
+#include <string>
#include <utility>
namespace MyGrate {
@@ -30,6 +31,24 @@ namespace MyGrate {
i /= 100;
return r;
}
+
+ template<typename T>
+ concept Stringable = requires(T a)
+ {
+ {
+ std::to_string(a)
+ } -> std::same_as<std::string>;
+ };
+ template<typename T>
+ concept Viewable = requires(T a)
+ {
+ {
+ a.data()
+ } -> std::convertible_to<const char *>;
+ {
+ a.size()
+ } -> std::integral;
+ };
}
#endif
diff --git a/lib/input/mysqlConn.cpp b/lib/input/mysqlConn.cpp
index 3a2c9f4..179f9d5 100644
--- a/lib/input/mysqlConn.cpp
+++ b/lib/input/mysqlConn.cpp
@@ -1,9 +1,18 @@
#include "mysqlConn.h"
#include "helpers.h"
+#include <cstddef>
+#include <cstring>
+#include <dbTypes.h>
+#include <memory>
#include <mysql.h>
+#include <mysql_types.h>
#include <stdexcept>
+#include <variant>
+#include <vector>
namespace MyGrate::Input {
+ using StmtPtr = std::unique_ptr<MYSQL_STMT, decltype(&mysql_stmt_close)>;
+
MySQLConn::MySQLConn(
const char * const host, const char * const user, const char * const pass, unsigned short port) :
st_mysql {}
@@ -26,4 +35,73 @@ namespace MyGrate::Input {
{
verify<std::runtime_error>(!mysql_query(this, q), q);
}
+
+ struct Bindings {
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ explicit Bindings(const std::initializer_list<DbValue> & vs)
+ {
+ binds.reserve(vs.size());
+ extras.reserve(vs.size());
+ for (const auto & v : vs) {
+ std::visit(*this, v);
+ }
+ }
+ template<std::integral T>
+ void
+ operator()(const T & v)
+ {
+ auto & b = binds.emplace_back();
+ b.buffer_type = MySQL::CType<T>::type;
+ b.buffer = const_cast<T *>(&v);
+ b.is_unsigned = std::unsigned_integral<T>;
+ }
+ template<std::floating_point T>
+ void
+ operator()(const T & v)
+ {
+ auto & b = binds.emplace_back();
+ b.buffer_type = MySQL::CType<T>::type;
+ b.buffer = const_cast<T *>(&v);
+ }
+ template<Viewable T>
+ void
+ operator()(const T & v)
+ {
+ auto & b = binds.emplace_back();
+ b.buffer_type = MySQL::CType<T>::type;
+ b.buffer = const_cast<typename T::value_type *>(v.data());
+ b.length = &extras.emplace_back(v.size(), 0).len;
+ }
+ void
+ operator()(const std::nullptr_t &)
+ {
+ auto & b = binds.emplace_back();
+ b.buffer = nullptr;
+ b.is_null = &extras.emplace_back(0, 1).null;
+ }
+ template<typename T>
+ void
+ operator()(const T &)
+ {
+ throw std::runtime_error("Not implemented");
+ }
+ struct extra {
+ explicit extra(unsigned long l, my_bool n = 0) : len {l}, null {n} { }
+ unsigned long len;
+ my_bool null;
+ };
+ std::vector<MYSQL_BIND> binds;
+ std::vector<extra> extras;
+ };
+
+ void
+ MySQLConn::query(const char * const q, const std::initializer_list<DbValue> & vs)
+ {
+ StmtPtr stmt {mysql_stmt_init(this), &mysql_stmt_close};
+ verify<std::runtime_error>(!mysql_stmt_prepare(stmt.get(), q, strlen(q)), q);
+ verify<std::logic_error>(mysql_stmt_param_count(stmt.get()) == vs.size(), "Param count mismatch");
+ Bindings b {vs};
+ verify<std::runtime_error>(!mysql_stmt_bind_param(stmt.get(), b.binds.data()), "Param count mismatch");
+ verify<std::runtime_error>(!mysql_stmt_execute(stmt.get()), q);
+ }
}
diff --git a/lib/input/mysqlConn.h b/lib/input/mysqlConn.h
index 2f57f33..9e4ec25 100644
--- a/lib/input/mysqlConn.h
+++ b/lib/input/mysqlConn.h
@@ -1,15 +1,19 @@
#ifndef MYGRATE_INPUT_MYSQLCONN_H
#define MYGRATE_INPUT_MYSQLCONN_H
+#include <dbConn.h>
+#include <dbTypes.h>
+#include <initializer_list>
#include <mysql.h>
namespace MyGrate::Input {
- class MySQLConn : public MYSQL {
+ class MySQLConn : public MYSQL, public DbConn {
public:
MySQLConn(const char * const host, const char * const user, const char * const pass, unsigned short port);
~MySQLConn();
- void query(const char * const);
+ void query(const char * const) override;
+ void query(const char * const q, const std::initializer_list<DbValue> &) override;
};
}
diff --git a/lib/mysql_types.h b/lib/mysql_types.h
index af45b4f..4f5355c 100644
--- a/lib/mysql_types.h
+++ b/lib/mysql_types.h
@@ -2,34 +2,19 @@
#define MYGRATE_MYSQL_TYPES_H
#include "bitset.h"
+#include "dbTypes.h"
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <mysql.h>
-#include <span>
#include <string_view>
-#include <variant>
-
-struct timespec;
namespace MyGrate {
class RawDataReader;
namespace MySQL {
- struct Date {
- uint16_t year;
- uint8_t month;
- uint8_t day;
- };
- struct Time {
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
- };
- struct DateTime : public Date, public Time {
- };
- using Blob = std::span<const std::byte>;
template<enum_field_types, bool /*unsigned*/ = false> struct Type;
+ template<typename T> struct CType;
#define DEFINE_BASE_TYPE(ET, CT, MDS, SIGN) \
template<> struct Type<ET, SIGN> { \
@@ -37,6 +22,11 @@ namespace MyGrate {
constexpr static size_t md_bytes {MDS}; \
static C read(RawDataReader & md, RawDataReader & data); \
}
+#define DEFINE_CTYPE(ET, CT) \
+ template<> struct CType<CT> { \
+ using C = CT; \
+ static constexpr enum_field_types type {ET}; \
+ }
#define DEFINE_TYPE(ET, CT, MDS) DEFINE_BASE_TYPE(ET, CT, MDS, false)
#define DEFINE_ITYPE(ET, BCT, MDS) \
DEFINE_BASE_TYPE(ET, BCT, MDS, false); \
@@ -74,12 +64,22 @@ namespace MyGrate {
DEFINE_TYPE(MYSQL_TYPE_JSON, std::string_view, 2);
DEFINE_TYPE(MYSQL_TYPE_GEOMETRY, Blob, 1);
+ DEFINE_CTYPE(MYSQL_TYPE_DOUBLE, double);
+ DEFINE_CTYPE(MYSQL_TYPE_FLOAT, float);
+ DEFINE_CTYPE(MYSQL_TYPE_SHORT, int16_t);
+ DEFINE_CTYPE(MYSQL_TYPE_LONG, int32_t);
+ DEFINE_CTYPE(MYSQL_TYPE_LONGLONG, int64_t);
+ DEFINE_CTYPE(MYSQL_TYPE_TINY, int8_t);
+ DEFINE_CTYPE(MYSQL_TYPE_SHORT, uint16_t);
+ DEFINE_CTYPE(MYSQL_TYPE_LONG, uint32_t);
+ DEFINE_CTYPE(MYSQL_TYPE_LONGLONG, uint64_t);
+ DEFINE_CTYPE(MYSQL_TYPE_TINY, uint8_t);
+ DEFINE_CTYPE(MYSQL_TYPE_STRING, std::string_view);
+ DEFINE_CTYPE(MYSQL_TYPE_BLOB, Blob);
+
#undef DEFINE_ITYPE
#undef DEFINE_USTYPE
#undef DEFINE_TYPE
-
- using FieldValue = std::variant<std::nullptr_t, double, float, int8_t, uint8_t, int16_t, uint16_t, int32_t,
- uint32_t, int64_t, uint64_t, timespec, Date, Time, DateTime, std::string_view, BitSet, Blob>;
}
}
diff --git a/lib/output/pq/pqConn.cpp b/lib/output/pq/pqConn.cpp
index 78cdc06..4f55ba8 100644
--- a/lib/output/pq/pqConn.cpp
+++ b/lib/output/pq/pqConn.cpp
@@ -1,8 +1,17 @@
#include "pqConn.h"
+#include <dbTypes.h>
#include <helpers.h>
+#include <libpq-fe.h>
+#include <memory>
+#include <sstream>
#include <stdexcept>
+#include <string>
+#include <variant>
+#include <vector>
namespace MyGrate::Output::Pq {
+ using ResPtr = std::unique_ptr<PGresult, decltype(&PQclear)>;
+
PqConn::PqConn(const char * const str) : conn {PQconnectdb(str)}
{
verify<std::runtime_error>(PQstatus(conn) == CONNECTION_OK, "Connection failure");
@@ -15,6 +24,67 @@ namespace MyGrate::Output::Pq {
}
void
+ PqConn::query(const char * const q)
+ {
+ ResPtr res {PQexec(conn, q), &PQclear};
+ verify<std::runtime_error>(PQresultStatus(res.get()) == PGRES_COMMAND_OK, q);
+ }
+
+ struct Bindings {
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ explicit Bindings(const std::initializer_list<DbValue> & vs)
+ {
+ bufs.reserve(vs.size());
+ values.reserve(vs.size());
+ lengths.reserve(vs.size());
+ for (const auto & v : vs) {
+ std::visit(*this, v);
+ }
+ }
+ template<Stringable T>
+ void
+ operator()(const T & v)
+ {
+ bufs.emplace_back(std::to_string(v));
+ const auto & vw {bufs.back()};
+ values.emplace_back(vw.data());
+ lengths.emplace_back(vw.length());
+ }
+ template<Viewable T>
+ void
+ operator()(const T & v)
+ {
+ values.emplace_back(v.data());
+ lengths.emplace_back(v.size());
+ }
+ template<typename T>
+ void
+ operator()(const T &)
+ {
+ throw std::runtime_error("Not implemented");
+ }
+ void
+ operator()(const std::nullptr_t &)
+ {
+ values.emplace_back(nullptr);
+ lengths.emplace_back(0);
+ }
+
+ std::vector<std::string> bufs;
+ std::vector<const char *> values;
+ std::vector<int> lengths;
+ };
+
+ void
+ PqConn::query(const char * const q, const std::initializer_list<DbValue> & vs)
+ {
+ Bindings b {vs};
+ ResPtr res {PQexecParams(conn, q, (int)vs.size(), nullptr, b.values.data(), b.lengths.data(), nullptr, 0),
+ &PQclear};
+ verify<std::runtime_error>(PQresultStatus(res.get()) == PGRES_COMMAND_OK, q);
+ }
+
+ void
PqConn::notice_processor(void * p, const char * n)
{
return static_cast<PqConn *>(p)->notice_processor(n);
diff --git a/lib/output/pq/pqConn.h b/lib/output/pq/pqConn.h
index bcf30b6..613af6f 100644
--- a/lib/output/pq/pqConn.h
+++ b/lib/output/pq/pqConn.h
@@ -1,14 +1,20 @@
#ifndef MYGRATE_OUTPUT_PQ_PQCONN_H
#define MYGRATE_OUTPUT_PQ_PQCONN_H
+#include <dbConn.h>
+#include <dbTypes.h>
+#include <initializer_list>
#include <libpq-fe.h>
namespace MyGrate::Output::Pq {
- class PqConn {
+ class PqConn : public DbConn {
public:
explicit PqConn(const char * const str);
virtual ~PqConn();
+ void query(const char * const) override;
+ void query(const char * const, const std::initializer_list<DbValue> &) override;
+
private:
static void notice_processor(void *, const char *);
virtual void notice_processor(const char *) const;
diff --git a/lib/row.cpp b/lib/row.cpp
index 65ac591..9d81906 100644
--- a/lib/row.cpp
+++ b/lib/row.cpp
@@ -1,6 +1,7 @@
#include "row.h"
#include "bitset.h"
#include "mariadb_repl.h"
+#include "mysql_types.h"
#include "rawDataReader.h"
#include <cstddef>
#include <mysql.h>
diff --git a/lib/row.h b/lib/row.h
index a40b1b2..35d8bcd 100644
--- a/lib/row.h
+++ b/lib/row.h
@@ -1,7 +1,7 @@
#ifndef MYGRATE_ROW_H
#define MYGRATE_ROW_H
-#include "mysql_types.h"
+#include "dbTypes.h"
#include <utility>
#include <vector>
namespace MyGrate {
@@ -11,7 +11,7 @@ struct st_mariadb_rpl_rows_event;
struct st_mariadb_rpl_table_map_event;
namespace MyGrate {
- class Row : public std::vector<MySQL::FieldValue> {
+ class Row : public std::vector<DbValue> {
public:
Row(const st_mariadb_rpl_rows_event &, const st_mariadb_rpl_table_map_event &);
diff --git a/lib/streamSupport.cpp b/lib/streamSupport.cpp
index acf6f7e..32c1fce 100644
--- a/lib/streamSupport.cpp
+++ b/lib/streamSupport.cpp
@@ -1,7 +1,7 @@
#include "streamSupport.h"
#include "bitset.h"
#include "compileTimeFormatter.h"
-#include "mysql_types.h"
+#include "dbTypes.h"
#include <cstdint>
#include <string_view>
#include <type_traits>
@@ -35,21 +35,21 @@ namespace std {
}
std::ostream &
- operator<<(std::ostream & s, const MyGrate::MySQL::Date & d)
+ operator<<(std::ostream & s, const MyGrate::Date & d)
{
return AdHoc::scprintf<"%04d-%02d-%02d">(s, d.year, d.month, d.day);
}
std::ostream &
- operator<<(std::ostream & s, const MyGrate::MySQL::Time & t)
+ operator<<(std::ostream & s, const MyGrate::Time & t)
{
return AdHoc::scprintf<"%02d:%02d:%02d">(s, t.hour, t.minute, t.second);
}
std::ostream &
- operator<<(std::ostream & s, const MyGrate::MySQL::DateTime & dt)
+ operator<<(std::ostream & s, const MyGrate::DateTime & dt)
{
- return AdHoc::scprintf<"%? %?">(s, (const MyGrate::MySQL::Date)dt, (const MyGrate::MySQL::Time)dt);
+ return AdHoc::scprintf<"%? %?">(s, (const MyGrate::Date)dt, (const MyGrate::Time)dt);
}
std::ostream &
diff --git a/lib/streamSupport.h b/lib/streamSupport.h
index 60e68d3..cab62e6 100644
--- a/lib/streamSupport.h
+++ b/lib/streamSupport.h
@@ -11,14 +11,8 @@
#include <vector>
namespace MyGrate {
class BitSet;
-}
-namespace MyGrate::MySQL {
struct Date;
-}
-namespace MyGrate::MySQL {
struct DateTime;
-}
-namespace MyGrate::MySQL {
struct Time;
}
struct timespec;
@@ -33,11 +27,11 @@ namespace std {
std::ostream & operator<<(std::ostream & s, const timespec & ts);
- std::ostream & operator<<(std::ostream & s, const MyGrate::MySQL::Date & d);
+ std::ostream & operator<<(std::ostream & s, const MyGrate::Date & d);
- std::ostream & operator<<(std::ostream & s, const MyGrate::MySQL::Time & t);
+ std::ostream & operator<<(std::ostream & s, const MyGrate::Time & t);
- std::ostream & operator<<(std::ostream & s, const MyGrate::MySQL::DateTime & dt);
+ std::ostream & operator<<(std::ostream & s, const MyGrate::DateTime & dt);
std::ostream & operator<<(std::ostream & s, const MyGrate::BitSet & bs);