From 046cdae1a14a686238ab91b1f883335b2de5a78c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 1 Jun 2021 00:17:38 +0100 Subject: Generate DbStmt templates from .sql files m4 generator and related code. Reshuffles some CTF stuff to avoid pulling in all of CTF and iostream for its fixed_string. Moves CTF out of AdHoc namespace. Add some initial SQL statements. --- Jamroot.jam | 21 +++++++++ lib/Jamfile.jam | 2 +- lib/compileTimeFormatter.h | 72 +++++------------------------- lib/dbStmt.h | 4 +- lib/fixedString.h | 59 ++++++++++++++++++++++++ lib/genstmt.m4 | 8 ++++ lib/input/sql/showMasterStatus.sql | 1 + lib/output/dumpToConsole.cpp | 14 +++--- lib/output/pq/pqStmt.cpp | 2 +- lib/output/pq/sql/selectColumns.sql | 6 +++ lib/output/pq/sql/selectSource.sql | 3 ++ lib/output/pq/sql/selectTables.sql | 6 +++ lib/output/pq/sql/updateSourcePosition.sql | 4 ++ lib/streamSupport.cpp | 12 ++--- test/test-mysql.cpp | 3 +- test/test-postgresql.cpp | 2 +- 16 files changed, 137 insertions(+), 82 deletions(-) create mode 100644 lib/fixedString.h create mode 100644 lib/genstmt.m4 create mode 100644 lib/input/sql/showMasterStatus.sql create mode 100644 lib/output/pq/sql/selectColumns.sql create mode 100644 lib/output/pq/sql/selectSource.sql create mode 100644 lib/output/pq/sql/selectTables.sql create mode 100644 lib/output/pq/sql/updateSourcePosition.sql diff --git a/Jamroot.jam b/Jamroot.jam index bb22c83..883aaf0 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -4,6 +4,9 @@ using clang : 12 ; using pkg-config ; import pkg-config ; import testing ; +import type : register ; +import generators : register-standard ; +import regex : replace ; pkg-config.import libmariadb ; pkg-config.import libpq ; @@ -37,3 +40,21 @@ project : requirements build-project main ; build-project test ; + +path-constant root : . ; + +type.register SQL : sql ; + +generators.register-standard embed.sql : SQL : CPP H ; + +actions embed.sql +{ + echo "#include \"$(2:B).h\"" > $(1[1]) + m4 -DSOURCE=$(2) -DNS=$(NS) -DNAME=$(2:B) > $(1[2]) lib/genstmt.m4 +} +rule embed.sql ( targets * : sources * : properties * ) +{ + DEPENDS $(targets) : $(root)/lib/genstmt.m4 ; + NS on $(targets) = [ replace $(sources:D) "/" "::" ] ; +} +IMPORT $(__name__) : embed.sql : : embed.sql ; diff --git a/lib/Jamfile.jam b/lib/Jamfile.jam index c54dabc..d805201 100644 --- a/lib/Jamfile.jam +++ b/lib/Jamfile.jam @@ -1,5 +1,5 @@ lib mygrate : - [ glob-tree *.cpp ] + [ glob-tree *.cpp *.sql : bin ] : static . diff --git a/lib/compileTimeFormatter.h b/lib/compileTimeFormatter.h index 17da62e..09aae53 100644 --- a/lib/compileTimeFormatter.h +++ b/lib/compileTimeFormatter.h @@ -1,6 +1,7 @@ -#ifndef ADHOCUTIL_COMPILE_TIME_FORMATTER_H -#define ADHOCUTIL_COMPILE_TIME_FORMATTER_H +#ifndef MYGRATE_COMPILE_TIME_FORMATTER_H +#define MYGRATE_COMPILE_TIME_FORMATTER_H +#include "fixedString.h" #include #include #include @@ -9,7 +10,7 @@ #include // IWYU pragma: export #include -namespace AdHoc { +namespace MyGrate { // Template char utils template constexpr bool @@ -235,82 +236,29 @@ namespace AdHoc { }; }; - // New C++20 implementation - namespace support { - template class basic_fixed_string { - public: - // cppcheck-suppress noExplicitConstructor - constexpr basic_fixed_string(const CharT (&str)[N + 1]) - { - for (decltype(N) x = 0; x < N; x++) { - arr.at(x) = str[x]; - } - arr.at(N) = '\0'; - } - constexpr basic_fixed_string(const CharT * str, decltype(N) len) - { - for (decltype(N) x = 0; x < len; x++) { - arr.at(x) = str[x]; - } - arr.at(N) = '\0'; - } - constexpr const char * - s() const - { - return arr.data(); - } - constexpr operator const char *() const - { - return s(); - } - constexpr std::string_view - v() const - { - return {arr.data(), arr.size() - 1}; - } - constexpr auto & - operator[](std::size_t n) const - { - return arr[n]; - } - constexpr auto - size() const - { - return arr.size() - 1; - } - - std::array arr; - }; - - template - basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string; - } - - template class LiteralFormatter : public FormatterDetail { + template class LiteralFormatter : public FormatterDetail { }; template class Formatter : - public FormatterDetail::type, L>(S, L), L> { + public FormatterDetail::type, L>(S, L), L> { }; -#define AdHocFormatter(name, str) using name = ::AdHoc::LiteralFormatter - - template + template inline auto scprintf(const Pn &... pn) { return FormatterDetail::get(pn...); } - template + template inline auto & scprintf(stream & strm, const Pn &... pn) { return FormatterDetail::write(strm, pn...); } - template + template inline auto & cprintf(const Pn &... pn) { @@ -327,7 +275,7 @@ namespace AdHoc { #include #include -namespace AdHoc { +namespace MyGrate { #define BASICCONV(PARAMTYPE, OP, ...) \ StreamWriterT(__VA_ARGS__) { \ template \ diff --git a/lib/dbStmt.h b/lib/dbStmt.h index 3e98b34..81621de 100644 --- a/lib/dbStmt.h +++ b/lib/dbStmt.h @@ -1,7 +1,7 @@ #ifndef MYGRATE_DBSTMT_H #define MYGRATE_DBSTMT_H -#include +#include "fixedString.h" #include #include #include @@ -12,7 +12,7 @@ namespace MyGrate { class DbConn; enum class ParamMode { None, DollarNum, QMark }; - template class DbStmt { + template class DbStmt { public: // This don't account for common table expressions, hopefully won't need those :) static constexpr auto isSelect {S.v().starts_with("SELECT") || S.v().starts_with("SHOW") diff --git a/lib/fixedString.h b/lib/fixedString.h new file mode 100644 index 0000000..df0529a --- /dev/null +++ b/lib/fixedString.h @@ -0,0 +1,59 @@ +#ifndef MYGRATE_SUPPORT_FIXEDSTRING_H +#define MYGRATE_SUPPORT_FIXEDSTRING_H + +#include +#include +#include + +namespace MyGrate::Support { + template class basic_fixed_string { + public: + // cppcheck-suppress noExplicitConstructor + constexpr basic_fixed_string(const CharT (&str)[N + 1]) + { + for (decltype(N) x = 0; x < N; x++) { + arr.at(x) = str[x]; + } + arr.at(N) = '\0'; + } + constexpr basic_fixed_string(const CharT * str, decltype(N) len) + { + for (decltype(N) x = 0; x < len; x++) { + arr.at(x) = str[x]; + } + arr.at(N) = '\0'; + } + constexpr const char * + s() const + { + return arr.data(); + } + constexpr operator const char *() const + { + return s(); + } + constexpr std::string_view + v() const + { + return {arr.data(), arr.size() - 1}; + } + constexpr auto & + operator[](std::size_t n) const + { + return arr[n]; + } + constexpr auto + size() const + { + return arr.size() - 1; + } + + std::array arr; + }; + + template + basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string; + +} + +#endif diff --git a/lib/genstmt.m4 b/lib/genstmt.m4 new file mode 100644 index 0000000..b0f3255 --- /dev/null +++ b/lib/genstmt.m4 @@ -0,0 +1,8 @@ +// NAME +#include +#include + +namespace MyGrate::NS { + using NAME = ::MyGrate::DbStmt; +} diff --git a/lib/input/sql/showMasterStatus.sql b/lib/input/sql/showMasterStatus.sql new file mode 100644 index 0000000..5746be2 --- /dev/null +++ b/lib/input/sql/showMasterStatus.sql @@ -0,0 +1 @@ +SHOW MASTER STATUS diff --git a/lib/output/dumpToConsole.cpp b/lib/output/dumpToConsole.cpp index 81d9edc..1085bb5 100644 --- a/lib/output/dumpToConsole.cpp +++ b/lib/output/dumpToConsole.cpp @@ -17,7 +17,7 @@ namespace MyGrate::Output { DumpToConsole::tableMap(MyGrate::MariaDB_Event_Ptr event) { const auto & tm = event->event.table_map; - AdHoc::scprintf<"Table map %?.%? -> %?\n">(std::cout, tm.database, tm.table, tm.table_id); + scprintf<"Table map %?.%? -> %?\n">(std::cout, tm.database, tm.table, tm.table_id); EventHandlerBase::tableMap(std::move(event)); } @@ -25,7 +25,7 @@ namespace MyGrate::Output { DumpToConsole::insertRow(MyGrate::MariaDB_Event_Ptr event) { const auto & rs = event->event.rows; - AdHoc::scprintf<"Insert into %?\n">(std::cout, rs.table_id); + scprintf<"Insert into %?\n">(std::cout, rs.table_id); dumpRowData(event->event.rows); } @@ -33,7 +33,7 @@ namespace MyGrate::Output { DumpToConsole::updateRow(MyGrate::MariaDB_Event_Ptr event) { const auto & rs = event->event.rows; - AdHoc::scprintf<"Update %?\n">(std::cout, rs.table_id); + scprintf<"Update %?\n">(std::cout, rs.table_id); dumpRowPairData(event->event.rows); } @@ -41,7 +41,7 @@ namespace MyGrate::Output { DumpToConsole::deleteRow(MyGrate::MariaDB_Event_Ptr event) { const auto & rs = event->event.rows; - AdHoc::scprintf<"Delete from %?\n">(std::cout, rs.table_id); + scprintf<"Delete from %?\n">(std::cout, rs.table_id); dumpRowData(event->event.rows); } @@ -50,19 +50,19 @@ namespace MyGrate::Output { void operator()(const T & v) const { - AdHoc::scprintf<"\t\t%?\n">(std::cout, v); + scprintf<"\t\t%?\n">(std::cout, v); } void operator()(const uint8_t & v) const { - AdHoc::scprintf<"\t\t%d\n">(std::cout, v); + scprintf<"\t\t%d\n">(std::cout, v); } void operator()(const int8_t & v) const { - AdHoc::scprintf<"\t\t%d\n">(std::cout, v); + scprintf<"\t\t%d\n">(std::cout, v); } }; diff --git a/lib/output/pq/pqStmt.cpp b/lib/output/pq/pqStmt.cpp index 04b48c6..078c239 100644 --- a/lib/output/pq/pqStmt.cpp +++ b/lib/output/pq/pqStmt.cpp @@ -46,7 +46,7 @@ namespace MyGrate::Output::Pq { if (const auto i = c->stmts.find(q); i != c->stmts.end()) { return i->second; } - auto nam {AdHoc::scprintf<"pst%0x">(c->stmts.size())}; + auto nam {scprintf<"pst%0x">(c->stmts.size())}; ResPtr res {PQprepare(c->conn.get(), nam.c_str(), q, (int)n, nullptr), PQclear}; verify(PQresultStatus(res.get()) == PGRES_COMMAND_OK, q); return c->stmts.emplace(q, std::move(nam)).first->second; diff --git a/lib/output/pq/sql/selectColumns.sql b/lib/output/pq/sql/selectColumns.sql new file mode 100644 index 0000000..e9cd107 --- /dev/null +++ b/lib/output/pq/sql/selectColumns.sql @@ -0,0 +1,6 @@ +SELECT t.table_name, STRING_AGG(c.column_name, '|' ORDER BY c.ordinal_position) +FROM mygrate.source s + JOIN information_schema.tables t USING(table_schema) + LEFT OUTER JOIN information_schema.columns c USING(table_schema, table_name) +WHERE s.id = $1 +GROUP BY t.table_name diff --git a/lib/output/pq/sql/selectSource.sql b/lib/output/pq/sql/selectSource.sql new file mode 100644 index 0000000..3048410 --- /dev/null +++ b/lib/output/pq/sql/selectSource.sql @@ -0,0 +1,3 @@ +SELECT host, username, password, port, filename, position, serverid, table_schema +FROM mygrate.source s +WHERE s.id = $1 diff --git a/lib/output/pq/sql/selectTables.sql b/lib/output/pq/sql/selectTables.sql new file mode 100644 index 0000000..389dfe2 --- /dev/null +++ b/lib/output/pq/sql/selectTables.sql @@ -0,0 +1,6 @@ +SELECT t.table_name, STRING_AGG(k.column_name, '|' ORDER BY k.ordinal_position) pk_cols +FROM mygrate.source s + JOIN information_schema.tables t USING(table_schema) + LEFT OUTER JOIN information_schema.key_column_usage k USING(table_schema, table_name) +WHERE s.id = $1 +GROUP BY t.table_name diff --git a/lib/output/pq/sql/updateSourcePosition.sql b/lib/output/pq/sql/updateSourcePosition.sql new file mode 100644 index 0000000..3d3d665 --- /dev/null +++ b/lib/output/pq/sql/updateSourcePosition.sql @@ -0,0 +1,4 @@ +UPDATE mygrate.source SET + filename = $1, + position = $2 +WHERE id = $3 diff --git a/lib/streamSupport.cpp b/lib/streamSupport.cpp index 32c1fce..2665b98 100644 --- a/lib/streamSupport.cpp +++ b/lib/streamSupport.cpp @@ -12,7 +12,7 @@ namespace std { std::ostream & operator<<(std::ostream & strm, const std::byte byt) { - return AdHoc::scprintf<"%#02x">(strm, std::to_integer(byt)); + return MyGrate::scprintf<"%#02x">(strm, std::to_integer(byt)); } std::ostream & @@ -24,32 +24,32 @@ namespace std { std::ostream & operator<<(std::ostream & s, const tm & tm) { - return AdHoc::scprintf<"%04d-%02d-%02d %02d:%02d:%02d">( + return MyGrate::scprintf<"%04d-%02d-%02d %02d:%02d:%02d">( s, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } std::ostream & operator<<(std::ostream & s, const timespec & ts) { - return AdHoc::scprintf<"%d.%09d">(s, ts.tv_sec, ts.tv_nsec); + return MyGrate::scprintf<"%d.%09d">(s, ts.tv_sec, ts.tv_nsec); } std::ostream & operator<<(std::ostream & s, const MyGrate::Date & d) { - return AdHoc::scprintf<"%04d-%02d-%02d">(s, d.year, d.month, d.day); + return MyGrate::scprintf<"%04d-%02d-%02d">(s, d.year, d.month, d.day); } std::ostream & operator<<(std::ostream & s, const MyGrate::Time & t) { - return AdHoc::scprintf<"%02d:%02d:%02d">(s, t.hour, t.minute, t.second); + return MyGrate::scprintf<"%02d:%02d:%02d">(s, t.hour, t.minute, t.second); } std::ostream & operator<<(std::ostream & s, const MyGrate::DateTime & dt) { - return AdHoc::scprintf<"%? %?">(s, (const MyGrate::Date)dt, (const MyGrate::Time)dt); + return MyGrate::scprintf<"%? %?">(s, (const MyGrate::Date)dt, (const MyGrate::Time)dt); } std::ostream & diff --git a/test/test-mysql.cpp b/test/test-mysql.cpp index 8710c8b..7c12f9a 100644 --- a/test/test-mysql.cpp +++ b/test/test-mysql.cpp @@ -1,13 +1,12 @@ #define BOOST_TEST_MODULE MySQL #include -#include -#include #include #include #include #include #include +#include #include #include #include diff --git a/test/test-postgresql.cpp b/test/test-postgresql.cpp index e89e031..a24acb8 100644 --- a/test/test-postgresql.cpp +++ b/test/test-postgresql.cpp @@ -1,11 +1,11 @@ #define BOOST_TEST_MODULE PostgreSQL #include -#include #include #include #include #include +#include #include #include #include -- cgit v1.2.3