Skip to content

Commit

Permalink
fixed reading of null values for all backends
Browse files Browse the repository at this point in the history
  • Loading branch information
zussel committed Jan 15, 2024
1 parent 650e534 commit 8256f2e
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 15 deletions.
37 changes: 37 additions & 0 deletions include/matador/db/postgresql/postgresql_getvalue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ namespace detail {
template < typename T, typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value && !std::is_same<T, char>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
val = 0;
return;
}
auto value = PQgetvalue(res, (int)row, (int)col);

if (strlen(value) == 0) {
Expand All @@ -31,6 +35,10 @@ std::is_unsigned<T>::value &&
>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
val = 0;
return;
}
auto value = PQgetvalue(res, (int)row, (int)col);

if (strlen(value) == 0) {
Expand All @@ -43,6 +51,10 @@ void get_value(PGresult *res, size_t row, size_t col, T &val)
template < typename T, typename std::enable_if<std::is_same<T, bool>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
val = false;
return;
}
auto value = PQgetvalue(res, (int)row, (int)col);

if (strlen(value) == 0) {
Expand All @@ -55,6 +67,10 @@ void get_value(PGresult *res, size_t row, size_t col, T &val)
template < typename T, typename std::enable_if<std::is_same<T, char>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
val = 0;
return;
}
auto value = PQgetvalue(res, (int)row, (int)col);

if (strlen(value) == 0) {
Expand All @@ -67,6 +83,10 @@ void get_value(PGresult *res, size_t row, size_t col, T &val)
template < typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
val = 0;
return;
}
auto value = PQgetvalue(res, (int)row, (int)col);

if (strlen(value) == 0) {
Expand All @@ -79,24 +99,41 @@ void get_value(PGresult *res, size_t row, size_t col, T &val)
template < typename T, typename std::enable_if<std::is_same<T, std::string>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
val.clear();
return;
}
if (PQgetisnull(res, (int)row, (int)col) == 1) {
return;
}
val = PQgetvalue(res, (int)row, (int)col);
}

template < typename T, typename std::enable_if<std::is_same<T, std::string>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val, size_t)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
val.clear();
return;
}
val = PQgetvalue(res, (int)row, (int)col);
}

template < typename T, typename std::enable_if<std::is_same<T, matador::time>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
return;
}
val = matador::time::parse(PQgetvalue(res, (int)row, (int)col), "%Y-%m-%d %T.%f");
}

template < typename T, typename std::enable_if<std::is_same<T, matador::date>::value>::type* = nullptr>
void get_value(PGresult *res, size_t row, size_t col, T &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
return;
}
val.set(PQgetvalue(res, (int)row, (int)col), date_format::ISO8601);
}

Expand Down
12 changes: 10 additions & 2 deletions src/db/mssql/mssql_result.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ void mssql_result::read_column(const char *, size_type index, std::string &val)
if (SQL_SUCCEEDED(ret)) {
if (info > 0) {
val.assign(buf, info);
} else {
val.clear();
}
} else {
throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql");
Expand All @@ -189,6 +191,8 @@ void mssql_result::read_column(const char *, size_type index, std::string &val,
if (SQL_SUCCEEDED(ret)) {
if (info > 0) {
val.assign(buf.data(), info);
} else {
val.clear();
}
} else {
throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql");
Expand Down Expand Up @@ -225,7 +229,9 @@ void mssql_result::read_column(char const *, size_type index, date &x)
SQLLEN info = 0;
SQLRETURN ret = SQLGetData(stmt_, static_cast<SQLUSMALLINT>(index), SQL_C_TYPE_DATE, &ds, 0, &info);
if (SQL_SUCCEEDED(ret)) {
x.set(ds.day, ds.month, ds.year);
if (info != SQL_NULL_DATA) {
x.set(ds.day, ds.month, ds.year);
}
} else {
throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql");
}
Expand All @@ -238,7 +244,9 @@ void mssql_result::read_column(char const *, size_type index, time &x)
SQLLEN info = 0;
SQLRETURN ret = SQLGetData(stmt_, static_cast<SQLUSMALLINT>(index), SQL_C_TYPE_TIMESTAMP, &ts, 0, &info);
if (SQL_SUCCEEDED(ret)) {
x.set(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fraction / 1000 / 1000);
if (info != SQL_NULL_DATA) {
x.set(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fraction / 1000 / 1000);
}
} else {
throw_database_error(ret, SQL_HANDLE_STMT, stmt_, "mssql");
}
Expand Down
2 changes: 2 additions & 0 deletions src/db/mysql/mysql_result.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ void mysql_result::read_value(const char */*id*/, size_type index, std::string &
{
char *val = row_[index];
if (val == nullptr) {
value.clear();
return;
}
value.assign(val);
Expand All @@ -254,6 +255,7 @@ void mysql_result::read_value(const char */*id*/, size_type index, std::string &
{
char *val = row_[index];
if (val == nullptr) {
value.clear();
return;
}
value.assign(val);
Expand Down
6 changes: 6 additions & 0 deletions src/db/postgresql/postgresql_getvalue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ namespace detail {

void get_value(PGresult *res, size_t row, size_t col, char *val, size_t s)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
return;
}
auto value = PQgetvalue(res, (int)row, (int)col);

size_t len = strlen(value);
Expand All @@ -26,6 +29,9 @@ void get_value(PGresult *res, size_t row, size_t col, char *val, size_t s)

void get_value(PGresult *res, size_t row, size_t col, unsigned char &val)
{
if (PQgetisnull(res, (int)row, (int)col) == 1) {
return;
}
auto value = PQgetvalue(res, (int)row, (int)col);

if (strlen(value) == 0) {
Expand Down
22 changes: 15 additions & 7 deletions src/db/sqlite/sqlite_prepared_result.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ void sqlite_prepared_result::read_value(const char */*id*/, size_type index, std
{
auto s = (size_t)sqlite3_column_bytes(stmt_, index);
auto *text = (const char*)sqlite3_column_text(stmt_, index);
x.assign(text, s);
if (s > 0) {
x.assign(text, s);
}
}

void sqlite_prepared_result::read_value(const char */*id*/, size_type index, std::string &x, size_t /*size*/)
Expand Down Expand Up @@ -153,16 +155,22 @@ void sqlite_prepared_result::read_value(const char */*id*/, size_type index, cha

void sqlite_prepared_result::read_value(const char *id, size_type index, matador::date &x)
{
std::string val;
read_value(id, index, val);
x = matador::date::parse(val, date_format::ISO8601);
auto is_null = sqlite3_column_type(stmt_, index) == SQLITE_NULL;
auto s = (size_t)sqlite3_column_bytes(stmt_, index);
if (!is_null && s > 0) {
const auto *text = reinterpret_cast<const char *>( sqlite3_column_text(stmt_, index));
x = matador::date::parse(text, date_format::ISO8601);
}
}

void sqlite_prepared_result::read_value(const char *id, size_type index, matador::time &x)
{
std::string val;
read_value(id, index, val);
x = matador::time::parse(val, "%Y-%m-%dT%T.%f");
auto is_null = sqlite3_column_type(stmt_, index) == SQLITE_NULL;
auto s = (size_t)sqlite3_column_bytes(stmt_, index);
if (!is_null && s > 0) {
const auto *text = reinterpret_cast<const char *>( sqlite3_column_text(stmt_, index));
x = matador::time::parse(text, "%Y-%m-%dT%T.%f");
}
}

bool sqlite_prepared_result::prepare_fetch()
Expand Down
8 changes: 6 additions & 2 deletions src/db/sqlite/sqlite_result.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,17 @@ void sqlite_result::read_value(const char */*id*/, size_type index, std::string
void sqlite_result::read_value(const char */*id*/, size_type index, matador::date &x)
{
t_row::value_type val = result_[row_index_][index];
x.set(val, date_format::ISO8601);
if (strlen(val) > 0) {
x.set(val, date_format::ISO8601);
}
}

void sqlite_result::read_value(const char */*id*/, size_type index, matador::time &x)
{
t_row::value_type val = result_[row_index_][index];
x = matador::time::parse(val, "%Y-%m-%dT%T.%f");
if (strlen(val) > 0) {
x = matador::time::parse(val, "%Y-%m-%dT%T.%f");
}
}

bool sqlite_result::prepare_fetch()
Expand Down
12 changes: 8 additions & 4 deletions test/sql/QueryTestUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,19 +624,23 @@ void QueryTestUnit::test_null_column()
q.create("person", {
make_pk_column<long>("id"),
make_column<std::string>("name", 63),
make_column<unsigned>("age")
make_column<matador::date>("birthday")
});

q.execute(connection_);

q.insert("person", {"id", "age"}).values({1, 47}).execute(connection_);
q.insert("person", {"id", "name"}).values({1, "george"}).execute(connection_);
q.insert("person", {"id", "birthday"}).values({2, date{27, 11, 1954}}).execute(connection_);

auto res = q.select({"id", "name", "age"}).from("person").execute(connection_);
auto res = q.select({"id", "name", "birthday"}).from("person").execute(connection_);

std::vector<std::string> expected_names{"george", ""};
size_t index{0};
for (const auto& r : res) {
auto name = r->at<std::string>("name");
UNIT_EXPECT_TRUE(name.empty());
UNIT_EXPECT_EQUAL(name, expected_names[index++]);
}

q.drop("person").execute(connection_);
}

Expand Down

0 comments on commit 8256f2e

Please sign in to comment.