summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdbpp/command.h55
-rw-r--r--libdbpp/unittests/testUtils.cpp48
2 files changed, 103 insertions, 0 deletions
diff --git a/libdbpp/command.h b/libdbpp/command.h
index 6f66559..09377a9 100644
--- a/libdbpp/command.h
+++ b/libdbpp/command.h
@@ -103,6 +103,61 @@ namespace DB {
/// The SQL statement.
const std::string sql;
+ /// Bind a parameter by type based on C++ traits to parameter i.
+ template<typename O>
+ inline auto bindParam(unsigned int i, const O & o)
+ {
+ if constexpr (std::is_null_pointer<O>::value) {
+ bindNull(i);
+ }
+ else if constexpr (std::is_same<O, std::nullopt_t>::value) {
+ bindNull(i);
+ }
+ else if constexpr (std::is_same<O, bool>::value) {
+ bindParamB(i, o);
+ }
+ else if constexpr (std::is_floating_point<O>::value) {
+ bindParamF(i, o);
+ }
+ else if constexpr (std::is_same<O, boost::posix_time::time_duration>::value) {
+ bindParamT(i, o);
+ }
+ else if constexpr (std::is_same<O, boost::posix_time::ptime>::value) {
+ bindParamT(i, o);
+ }
+ else if constexpr (std::is_same<O, Blob>::value) {
+ bindParamBLOB(i, o);
+ }
+ else if constexpr (std::is_integral<O>::value && !std::is_pointer<O>::value) {
+ bindParamI(i, o);
+ }
+ else if constexpr (std::is_convertible<O, std::string_view>::value && std::is_pointer<O>::value) {
+ if (o) {
+ bindParamS(i, o);
+ }
+ else {
+ bindNull(i);
+ }
+ }
+ else if constexpr (std::is_same<O, Glib::ustring>::value) {
+ bindParamS(i, o);
+ }
+ else if constexpr (std::is_convertible<O, std::string_view>::value) {
+ bindParamS(i, o);
+ }
+ else if constexpr (std::is_constructible<bool, const O &>::value) {
+ if (o) {
+ bindParam(i, *o);
+ }
+ else {
+ bindNull(i);
+ }
+ }
+ else {
+ static_assert(!&o, "No suitable trait");
+ }
+ }
+
#define OPTWRAPPER(func) \
template<typename O> \
inline auto \
diff --git a/libdbpp/unittests/testUtils.cpp b/libdbpp/unittests/testUtils.cpp
index 0e90a94..67c1751 100644
--- a/libdbpp/unittests/testUtils.cpp
+++ b/libdbpp/unittests/testUtils.cpp
@@ -302,6 +302,54 @@ BOOST_AUTO_TEST_CASE( bindIntPtr )
BOOST_REQUIRE_EQUAL(159, total);
}
+BOOST_FIXTURE_TEST_CASE( traits_bind, DB::TestCore )
+{
+ auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));
+ auto cmd = db->select("select x is null, format('%s', x) from (select ? x) d");
+ auto check = [cmd](int line, const auto & v, bool isNull, const auto & strval) {
+ BOOST_TEST_CONTEXT("line " << line) {
+ cmd->bindParam(0, v);
+ for (const auto & [null, str] : cmd->as<bool, std::string_view>()) {
+ BOOST_CHECK_EQUAL(null, isNull);
+ BOOST_CHECK_EQUAL(str, strval);
+ }
+ }
+ };
+ check(__LINE__, std::nullopt, true, "");
+ check(__LINE__, nullptr, true, "");
+ check(__LINE__, testInt, false, "43");
+ check(__LINE__, std::make_unique<short>(testInt), false, "43");
+ check(__LINE__, std::unique_ptr<short>(), true, "");
+ check(__LINE__, (unsigned int)testInt, false, "43");
+ check(__LINE__, &testInt, false, "43");
+ check(__LINE__, testDouble, false, "3.14");
+ check(__LINE__, std::make_shared<float>(testDouble), false, "3.14");
+ check(__LINE__, std::shared_ptr<float>(), true, "");
+ check(__LINE__, (float)testDouble, false, "3.14");
+ check(__LINE__, &testDouble, false, "3.14");
+ check(__LINE__, testString, false, testString);
+ check(__LINE__, &testString, false, testString);
+ check(__LINE__, "str", false, "str");
+ check(__LINE__, "", false, "");
+ const char * const nullstr = nullptr;
+ check(__LINE__, nullstr, true, "");
+ const char * const str = "str";
+ check(__LINE__, str, false, "str");
+ check(__LINE__, std::string(), false, "");
+ check(__LINE__, std::string_view(), false, "");
+ check(__LINE__, Glib::ustring(), false, "");
+ check(__LINE__, Glib::ustring("foo"), false, "foo");
+ check(__LINE__, testDateTime, false, "2015-05-02T01:36:33");
+ check(__LINE__, testInterval, false, "01:02:03");
+ check(__LINE__, &testInterval, false, "01:02:03");
+ decltype(testInterval) * nullInterval = nullptr;
+ check(__LINE__, nullInterval, true, "");
+ check(__LINE__, true, false, "1");
+ check(__LINE__, false, false, "0");
+ check(__LINE__, std::optional<int>(4), false, "4");
+ check(__LINE__, std::optional<int>(), true, "");
+}
+
BOOST_AUTO_TEST_CASE( testBlobRaw )
{
DB::Blob ptr(this, 1);