summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdbpp/command.cpp19
-rw-r--r--libdbpp/command.h16
-rw-r--r--libdbpp/unittests/Jamfile.jam2
-rw-r--r--libdbpp/unittests/testUtils.cpp102
4 files changed, 139 insertions, 0 deletions
diff --git a/libdbpp/command.cpp b/libdbpp/command.cpp
index abbb53f..97a6518 100644
--- a/libdbpp/command.cpp
+++ b/libdbpp/command.cpp
@@ -17,3 +17,22 @@ DB::ParameterOutOfRange::ParameterOutOfRange()
{
}
+void
+DB::Command::bindParamS(unsigned int i, const char * const o)
+{
+ if (o)
+ bindParamS(i, Glib::ustring(o));
+ else
+ bindNull(i);
+}
+
+
+void
+DB::Command::bindParamS(unsigned int i, char * const o)
+{
+ if (o)
+ bindParamS(i, Glib::ustring(o));
+ else
+ bindNull(i);
+}
+
diff --git a/libdbpp/command.h b/libdbpp/command.h
index 3305342..ae18158 100644
--- a/libdbpp/command.h
+++ b/libdbpp/command.h
@@ -61,6 +61,22 @@ namespace DB {
/// The SQL statement.
const std::string sql;
+
+#define OPTWRAPPER(func) \
+ template<typename O> \
+ inline void func(unsigned int i, const O & o) { \
+ if (o) \
+ func(i, *o); \
+ else \
+ bindNull(i); \
+ }
+ OPTWRAPPER(bindParamI);
+ OPTWRAPPER(bindParamF);
+ OPTWRAPPER(bindParamS);
+ OPTWRAPPER(bindParamB);
+ OPTWRAPPER(bindParamT);
+ void bindParamS(unsigned int, const char * const);
+ void bindParamS(unsigned int, char * const);
};
typedef boost::shared_ptr<Command> CommandPtr;
}
diff --git a/libdbpp/unittests/Jamfile.jam b/libdbpp/unittests/Jamfile.jam
index 08bd027..93b26b3 100644
--- a/libdbpp/unittests/Jamfile.jam
+++ b/libdbpp/unittests/Jamfile.jam
@@ -3,6 +3,7 @@ import testing ;
path-constant me : . ;
lib boost_utf : : <name>boost_unit_test_framework ;
+lib IceUtil ;
run
testConnection.cpp
@@ -62,6 +63,7 @@ run
<library>..//adhocutil
<library>../../libpqpp//dbpp-postgresql
<library>boost_utf
+ <library>IceUtil
<dependency>util.sql
:
testUtils
diff --git a/libdbpp/unittests/testUtils.cpp b/libdbpp/unittests/testUtils.cpp
index ac9b7c1..cb660cc 100644
--- a/libdbpp/unittests/testUtils.cpp
+++ b/libdbpp/unittests/testUtils.cpp
@@ -3,11 +3,14 @@
#include <connection.h>
#include <selectcommand.h>
+#include <modifycommand.h>
#include <selectcommandUtil.impl.h>
#include <definedDirs.h>
#include <fstream>
#include <pq-mock.h>
#include <boost/date_time/posix_time/posix_time_io.hpp>
+#include <IceUtil/Exception.h>
+#include <IceUtil/Optional.h>
class StandardMockDatabase : public PQ::Mock {
public:
@@ -148,3 +151,102 @@ BOOST_AUTO_TEST_CASE( bulkLoadFile )
});
}
+BOOST_AUTO_TEST_CASE( nullBind )
+{
+ auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));
+ auto ins = db->modify("INSERT INTO forEachRow VALUES(?, ?, ?, ?, ?, ?)");
+ ins->bindParamI(0, boost::optional<int>());
+ ins->bindParamF(1, boost::optional<double>());
+ ins->bindParamS(2, boost::optional<Glib::ustring>());
+ ins->bindParamT(3, boost::optional<boost::posix_time::ptime>());
+ ins->bindParamT(4, boost::optional<boost::posix_time::time_duration>());
+ ins->bindParamB(5, boost::optional<bool>());
+ ins->execute();
+ auto sel = DB::SelectCommandPtr(db->newSelectCommand("SELECT a, b, c, d, e, f FROM forEachRow WHERE a IS NULL AND b IS NULL AND c IS NULL AND d IS NULL AND e IS NULL AND f IS NULL"));
+ unsigned int count = 0;
+ for (const auto & row : sel->as<>()) {
+ (void)row;
+ count += 1;
+ }
+ BOOST_REQUIRE_EQUAL(1, count);
+}
+
+BOOST_AUTO_TEST_CASE( iceNullBind )
+{
+ auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));
+ auto ins = db->modify("INSERT INTO forEachRow VALUES(?, ?, ?, ?, ?, ?)");
+ ins->bindParamI(0, IceUtil::Optional<int>());
+ ins->bindParamF(1, IceUtil::Optional<double>());
+ ins->bindParamS(2, IceUtil::Optional<Glib::ustring>());
+ ins->bindParamT(3, IceUtil::Optional<boost::posix_time::ptime>());
+ ins->bindParamT(4, IceUtil::Optional<boost::posix_time::time_duration>());
+ ins->bindParamB(5, IceUtil::Optional<bool>());
+ ins->execute();
+ auto sel = DB::SelectCommandPtr(db->newSelectCommand("SELECT a, b, c, d, e, f FROM forEachRow WHERE a IS NULL AND b IS NULL AND c IS NULL AND d IS NULL AND e IS NULL AND f IS NULL"));
+ unsigned int count = 0;
+ for (const auto & row : sel->as<>()) {
+ (void)row;
+ count += 1;
+ }
+ BOOST_REQUIRE_EQUAL(2, count);
+}
+
+BOOST_AUTO_TEST_CASE( charStarBindNull )
+{
+ auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));
+ db->modify("DELETE FROM forEachRow")->execute();
+ auto ins = db->modify("INSERT INTO forEachRow(a, c) VALUES(?, ?)");
+ char * cs = NULL;
+ char * cs2 = strdup("a thing");
+ ins->bindParamS(0, cs);
+ ins->bindParamS(1, cs2);
+ ins->execute();
+ const char * ccs = cs;
+ const char * ccs2 = cs2;
+ ins->bindParamS(0, ccs);
+ ins->bindParamS(1, ccs2);
+ ins->execute();
+ const char * const ccsc = ccs;
+ const char * const ccsc2 = ccs2;
+ ins->bindParamS(0, ccsc);
+ ins->bindParamS(1, ccsc2);
+ ins->execute();
+ free(cs2);
+ auto sel = DB::SelectCommandPtr(db->newSelectCommand("SELECT a, c FROM forEachRow"));
+ for (const auto & row : sel->as<boost::optional<int64_t>, boost::optional<std::string>>()) {
+ BOOST_REQUIRE(row[0].isNull());
+ BOOST_REQUIRE(!row[1].isNull());
+ }
+}
+
+BOOST_AUTO_TEST_CASE( bindIntPtr )
+{
+ auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));
+ db->modify("DELETE FROM forEachRow")->execute();
+ auto ins = db->modify("INSERT INTO forEachRow(a, b) VALUES(?, ?)");
+ int * is = NULL;
+ int * is2 = new int(53);
+ ins->bindParamI(0, is);
+ ins->bindParamI(1, is2);
+ ins->execute();
+ const int * cis = is;
+ const int * cis2 = is2;
+ ins->bindParamI(0, cis);
+ ins->bindParamI(1, cis2);
+ ins->execute();
+ const int * const cisc = cis;
+ const int * const cisc2 = cis2;
+ ins->bindParamI(0, cisc);
+ ins->bindParamI(1, cisc2);
+ ins->execute();
+ delete is2;
+ auto sel = DB::SelectCommandPtr(db->newSelectCommand("SELECT a, b FROM forEachRow"));
+ unsigned int total = 0;
+ for (const auto & row : sel->as<boost::optional<int64_t>, boost::optional<double>>()) {
+ BOOST_REQUIRE(row[0].isNull());
+ BOOST_REQUIRE(!row[1].isNull());
+ total += *row.value<1>();
+ }
+ BOOST_REQUIRE_EQUAL(159, total);
+}
+