fixed backend tests (progress)

This commit is contained in:
Sascha Kühl 2025-02-14 16:01:22 +01:00
parent d070a5a0ac
commit 6e64ba99de
6 changed files with 89 additions and 22 deletions

View File

@ -10,6 +10,7 @@
#include "matador/sql/internal/query_result_impl.hpp" #include "matador/sql/internal/query_result_impl.hpp"
#include <algorithm>
#include <sstream> #include <sstream>
namespace matador::backends::postgres { namespace matador::backends::postgres {
@ -79,6 +80,8 @@ utils::result<utils::version, utils::error> postgres_connection::server_version(
}); });
} }
utils::basic_type oid2type(Oid oid);
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_connection::fetch(const sql::query_context &context) { utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_connection::fetch(const sql::query_context &context) {
PGresult *res = PQexec(conn_, context.sql.c_str()); PGresult *res = PQexec(conn_, context.sql.c_str());
@ -86,16 +89,28 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_co
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, conn_, "Failed to fetch", context.sql)); return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, conn_, "Failed to fetch", context.sql));
} }
// std::vector<object::column_definition> prototype; // const auto is_unknown = std::all_of( context.prototype.begin(), context.prototype.end(), [](const object::attribute_definition &a) {return a.is_null();} );
// const auto num_col = PQnfields(res); // if (!is_unknown) {
// for (int i = 0; i < num_col; ++i) { // return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), context.prototype));
// const char *col_name = PQfname(res, i); // }
// auto type = PQftype(res, i);
// auto size = PQfmod(res, i);
// prototype.emplace_back(col_name);
// }
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), context.prototype)); std::vector<object::attribute_definition> prototype = context.prototype;
const auto num_col = PQnfields(res);
if (prototype.size() != num_col) {
return utils::failure(make_error(sql::error_code::FETCH_FAILED, res, conn_, "Number of received columns doesn't match expected columns.", context.sql));
}
for (int i = 0; i < num_col; ++i) {
if (!prototype.at(i).is_null()) {
continue;
}
const auto type = oid2type(PQftype(res, i));
// const char *col_name = PQfname(res, i);
// const auto size = PQfmod(res, i);
prototype.at(i).type(type);
}
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), prototype));
} }
std::string postgres_connection::generate_statement_name(const sql::query_context &query) { std::string postgres_connection::generate_statement_name(const sql::query_context &query) {
@ -141,6 +156,37 @@ utils::result<size_t, utils::error> postgres_connection::execute(const std::stri
return utils::ok(static_cast<size_t>(affected_rows)); return utils::ok(static_cast<size_t>(affected_rows));
} }
utils::basic_type oid2type(const Oid oid) {
switch (oid) {
case 16:
return utils::basic_type::type_bool;
case 17:
return utils::basic_type::type_blob;
case 18:
return utils::basic_type::type_int8;
case 21:
return utils::basic_type::type_int16;
case 23:
return utils::basic_type::type_int32;
case 20:
return utils::basic_type::type_int64;
case 24:
return utils::basic_type::type_text;
case 1043:
return utils::basic_type::type_varchar;
case 700:
return utils::basic_type::type_float;
case 701:
return utils::basic_type::type_double;
case 1082:
return utils::basic_type::type_date;
case 1114:
return utils::basic_type::type_time;
default:
return utils::basic_type::type_null;
}
}
utils::basic_type string2type(const char *type) { utils::basic_type string2type(const char *type) {
if (strcmp(type, "int2") == 0) { if (strcmp(type, "int2") == 0) {
return utils::basic_type::type_int16; return utils::basic_type::type_int16;

View File

@ -13,7 +13,7 @@
return "$" + std::to_string(index); return "$" + std::to_string(index);
}) })
.with_token_replace_map({ .with_token_replace_map({
{dialect_token::BEGIN_BINARY_DATA, "'"} {dialect_token::BEGIN_BINARY_DATA, "'\\x"}
}) })
.with_data_type_replace_map({ .with_data_type_replace_map({
{matador::utils::basic_type::type_int8, "SMALLINT"}, {matador::utils::basic_type::type_int8, "SMALLINT"},

View File

@ -131,7 +131,7 @@ result<DestType, conversion_error> to(const std::string &source, std::enable_if_
} }
template < typename DestType > template < typename DestType >
result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_integral_v<DestType> && std::is_unsigned_v<DestType>>* = nullptr) result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_integral_v<DestType> && std::is_unsigned_v<DestType> && !std::is_same_v<DestType, bool>>* = nullptr)
{ {
if (source.empty()) { if (source.empty()) {
return failure(conversion_error::MissingData/*, "failed to convert empty string"}*/); return failure(conversion_error::MissingData/*, "failed to convert empty string"}*/);
@ -167,17 +167,27 @@ result<DestType, conversion_error> to(const blob &source, std::enable_if_t<std::
return ok(source); return ok(source);
} }
// template < typename DestType >
// result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, blob>>* = nullptr) {
// if (source.empty()) {
// return failure(conversion_error::MissingData/*, "failed to convert empty string"}*/);
// }
//
// }
//
static std::unordered_map<std::string, bool> string_to_bool_map = { static std::unordered_map<std::string, bool> string_to_bool_map = {
{"true", true}, {"true", true},
{"t", true},
{"on", true}, {"on", true},
{"1", true}, {"1", true},
{"false", false}, {"false", false},
{"f", false},
{"off", false}, {"off", false},
{"0", false} {"0", false}
}; };
template < typename DestType, typename SourceType > template < typename DestType >
result<DestType, conversion_error> to(const SourceType &source, std::enable_if_t<std::is_same_v<SourceType, std::string> &&std::is_same_v<DestType, bool>>* = nullptr) { result<DestType, conversion_error> to(const std::string &source, std::enable_if_t<std::is_same_v<DestType, bool>>* = nullptr) {
if (source.empty()) { if (source.empty()) {
return failure(conversion_error::MissingData); return failure(conversion_error::MissingData);
} }
@ -188,6 +198,18 @@ result<DestType, conversion_error> to(const SourceType &source, std::enable_if_t
return ok(it->second); return ok(it->second);
} }
template < typename DestType >
result<DestType, conversion_error> to(const char *source, std::enable_if_t<std::is_same_v<DestType, bool>>* = nullptr) {
if (strlen(source) == 0) {
return failure(conversion_error::MissingData);
}
const auto it = string_to_bool_map.find(source);
if (it == string_to_bool_map.end()) {
return failure(conversion_error::NotConvertable);
}
return ok(it->second);
}
template < typename DestType, typename SourceType > template < typename DestType, typename SourceType >
result<DestType, conversion_error> to(const SourceType &source, std::enable_if_t<std::is_same_v<SourceType, bool> &&std::is_same_v<DestType, std::string>>* = nullptr) { result<DestType, conversion_error> to(const SourceType &source, std::enable_if_t<std::is_same_v<SourceType, bool> &&std::is_same_v<DestType, std::string>>* = nullptr) {
return ok(std::string(source ? "true" : "false")); return ok(std::string(source ? "true" : "false"));

View File

@ -1,6 +1,6 @@
#include "matador/query/attribute_string_writer.hpp" #include "matador/query/attribute_string_writer.hpp"
// #include "matador/sql/connection_impl.hpp" #include "matador/sql/interface/connection_impl.hpp"
#include <matador/utils/convert.hpp> #include <matador/utils/convert.hpp>
@ -56,13 +56,13 @@ void attribute_string_writer::write_value(size_t /*pos*/, const bool& x ) {
} }
void attribute_string_writer::write_value(size_t /*pos*/, const float& x ) { void attribute_string_writer::write_value(size_t /*pos*/, const float& x ) {
if (const auto res = utils::to<std::string>(x); res.is_error()) { if (const auto res = utils::to<std::string>(x); !res.is_error()) {
result_ = *res; result_ = *res;
} }
} }
void attribute_string_writer::write_value(size_t /*pos*/, const double& x ) { void attribute_string_writer::write_value(size_t /*pos*/, const double& x ) {
if (const auto res = utils::to<std::string>(x); res.is_error()) { if (const auto res = utils::to<std::string>(x); !res.is_error()) {
result_ = *res; result_ = *res;
} }
} }
@ -98,7 +98,7 @@ void attribute_string_writer::write_value(size_t /*pos*/, const utils::blob& x )
// MSSQL: 0x5468697320697320612062616E617279204461746120737472696E67 // MSSQL: 0x5468697320697320612062616E617279204461746120737472696E67
// Sqlite: X'5468697320697320612062616E617279204461746120737472696E67' // Sqlite: X'5468697320697320612062616E617279204461746120737472696E67'
if (conn_.has_value()) { if (conn_.has_value()) {
// result_ = dialect_.token_at(sql::dialect_token::BEGIN_BINARY_DATA) + conn_.value().get().to_escaped_string(x) + dialect_.token_at(sql::dialect_token::END_BINARY_DATA); result_ = dialect_.token_at(sql::dialect_token::BEGIN_BINARY_DATA) + conn_.value().get().to_escaped_string(x) + dialect_.token_at(sql::dialect_token::END_BINARY_DATA);
} else { } else {
result_ = dialect_.token_at(sql::dialect_token::BEGIN_BINARY_DATA) + dialect_.to_escaped_string(x) + dialect_.token_at(sql::dialect_token::END_BINARY_DATA); result_ = dialect_.token_at(sql::dialect_token::BEGIN_BINARY_DATA) + dialect_.to_escaped_string(x) + dialect_.token_at(sql::dialect_token::END_BINARY_DATA);
} }

View File

@ -74,7 +74,7 @@ TEST_CASE_METHOD( QueryFixture, "Insert and select basic datatypes", "[query][da
}; };
res = query::insert() res = query::insert()
.into("types", matador::sql::column_generator::generate<types>(schema, true)) .into("types", column_generator::generate<types>(schema, true))
.values(t) .values(t)
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());

View File

@ -50,8 +50,8 @@ TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record
tables_to_drop.emplace("types"); tables_to_drop.emplace("types");
auto cols = std::vector<std::string>{"id", auto cols = std::vector<std::string>{"id",
"val_char", "val_short", "val_int", "val_long", "val_long_long", "val_char", "val_short", "val_int", "val_long_long",
"val_uchar", "val_ushort", "val_uint", "val_ulong", "val_ulong_long", "val_uchar", "val_ushort", "val_uint", "val_ulong_long",
"val_bool", "val_bool",
"val_float", "val_double", "val_float", "val_double",
"val_string", "val_varchar", "val_string", "val_varchar",
@ -426,8 +426,7 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement with order by", "[query
REQUIRE(expected_names.empty()); REQUIRE(expected_names.empty());
} }
TEST_CASE_METHOD(QueryFixture, "Execute select statement with group by and order by", "[query][record]") TEST_CASE_METHOD(QueryFixture, "Execute select statement with group by and order by", "[query][record]") {
{
auto res = query::create() auto res = query::create()
.table("person", { .table("person", {
make_pk_column<uint32_t>("id"), make_pk_column<uint32_t>("id"),