finished postgres fetch
This commit is contained in:
parent
825e530a8d
commit
640dcfadb6
|
|
@ -32,14 +32,13 @@ public:
|
||||||
void read_value(const char *id, size_t index, char *value, size_t s) override;
|
void read_value(const char *id, size_t index, char *value, size_t s) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value) override;
|
void read_value(const char *id, size_t index, std::string &value) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value, size_t s) override;
|
void read_value(const char *id, size_t index, std::string &value, size_t s) override;
|
||||||
void read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PGresult *result_{};
|
PGresult *result_{};
|
||||||
|
|
||||||
size_t row_count_{};
|
size_t row_count_{};
|
||||||
size_t column_count_{};
|
size_t column_count_{};
|
||||||
size_t row_index_{0};
|
int row_index_{-1};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
#include "postgres_connection.hpp"
|
#include "postgres_connection.hpp"
|
||||||
#include "postgres_error.hpp"
|
#include "postgres_error.hpp"
|
||||||
|
#include "postgres_result_reader.hpp"
|
||||||
|
|
||||||
|
#include "matador/sql/record.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace matador::backends::postgres {
|
namespace matador::backends::postgres {
|
||||||
|
|
||||||
|
|
@ -41,7 +46,16 @@ std::unique_ptr<sql::query_result_impl> postgres_connection::fetch(const std::st
|
||||||
|
|
||||||
throw_postgres_error(res, conn_, "postgres", stmt);
|
throw_postgres_error(res, conn_, "postgres", stmt);
|
||||||
|
|
||||||
return {};
|
sql::record prototype;
|
||||||
|
auto ncol = PQnfields(res);
|
||||||
|
for (int i = 0; i < ncol; ++i) {
|
||||||
|
const char *col_name = PQfname(res, i);
|
||||||
|
auto type = PQftype(res, i);
|
||||||
|
auto size = PQfmod(res, i);
|
||||||
|
std::cout << "column " << col_name << ", type " << type << " (size: " << size << ")\n";
|
||||||
|
prototype.append({col_name});
|
||||||
|
}
|
||||||
|
return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), std::move(prototype)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_connection::prepare(const std::string &stmt)
|
void postgres_connection::prepare(const std::string &stmt)
|
||||||
|
|
@ -55,12 +69,67 @@ size_t postgres_connection::execute(const std::string &stmt)
|
||||||
|
|
||||||
throw_postgres_error(res, conn_, "postgres", stmt);
|
throw_postgres_error(res, conn_, "postgres", stmt);
|
||||||
|
|
||||||
return 0;
|
return sql::to_long_long(PQcmdTuples(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
sql::data_type_t string2type(const char *type)
|
||||||
|
{
|
||||||
|
if (strcmp(type, "int2") == 0) {
|
||||||
|
return sql::data_type_t::type_short;
|
||||||
|
} else if (strcmp(type, "int4") == 0) {
|
||||||
|
return sql::data_type_t::type_int;
|
||||||
|
} else if (strcmp(type, "int8") == 0) {
|
||||||
|
return sql::data_type_t::type_long_long;
|
||||||
|
} else if (strncmp(type, "int8", 6) == 0) {
|
||||||
|
return sql::data_type_t::type_long_long;
|
||||||
|
} else if (strcmp(type, "date") == 0) {
|
||||||
|
return sql::data_type_t::type_date;
|
||||||
|
} else if (strncmp(type, "timestamp", 8) == 0) {
|
||||||
|
return sql::data_type_t::type_time;
|
||||||
|
} else if (strcmp(type, "float4") == 0) {
|
||||||
|
return sql::data_type_t::type_float;
|
||||||
|
} else if (strcmp(type, "float8") == 0) {
|
||||||
|
return sql::data_type_t::type_double;
|
||||||
|
} else if (strncmp(type, "varchar", 7) == 0) {
|
||||||
|
return sql::data_type_t::type_varchar;
|
||||||
|
} else if (strncmp(type, "character varying", 7) == 0) {
|
||||||
|
return sql::data_type_t::type_varchar;
|
||||||
|
} else if (strncmp(type, "text", 0) == 0) {
|
||||||
|
return sql::data_type_t::type_text;
|
||||||
|
} else {
|
||||||
|
return sql::data_type_t::type_unknown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sql::record postgres_connection::describe(const std::string &table)
|
sql::record postgres_connection::describe(const std::string &table)
|
||||||
{
|
{
|
||||||
return {};
|
std::string stmt(
|
||||||
|
"SELECT ordinal_position, column_name, udt_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_schema='public' AND table_name='" + table + "'");
|
||||||
|
|
||||||
|
PGresult *res = PQexec(conn_, stmt.c_str());
|
||||||
|
|
||||||
|
throw_postgres_error(res, conn_, "postgres", stmt);
|
||||||
|
|
||||||
|
postgres_result_reader reader(res);
|
||||||
|
sql::record prototype;
|
||||||
|
while (reader.fetch()) {
|
||||||
|
char *end = nullptr;
|
||||||
|
// Todo: Handle error
|
||||||
|
auto index = strtoul(reader.column(0), &end, 10);
|
||||||
|
std::string name = reader.column(1);
|
||||||
|
|
||||||
|
// Todo: extract size
|
||||||
|
auto type = (string2type(reader.column(2)));
|
||||||
|
end = nullptr;
|
||||||
|
utils::constraints options{};
|
||||||
|
if (strtoul(reader.column(4), &end, 10) == 0) {
|
||||||
|
options = utils::constraints::NOT_NULL;
|
||||||
|
}
|
||||||
|
// f.default_value(res->column(4));
|
||||||
|
prototype.append({name, type, {options}});
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool postgres_connection::exists(const std::string &table_name)
|
bool postgres_connection::exists(const std::string &table_name)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ size_t postgres_result_reader::column_count() const
|
||||||
|
|
||||||
const char *postgres_result_reader::column(size_t index) const
|
const char *postgres_result_reader::column(size_t index) const
|
||||||
{
|
{
|
||||||
return nullptr;
|
return PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool postgres_result_reader::fetch()
|
bool postgres_result_reader::fetch()
|
||||||
|
|
@ -99,22 +99,39 @@ void postgres_result_reader::read_value(const char *id, size_t index, double &va
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char *id, size_t index, char *value, size_t s)
|
void postgres_result_reader::read_value(const char *id, size_t index, char *value, size_t s)
|
||||||
{
|
{
|
||||||
|
auto *val = PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index));
|
||||||
|
|
||||||
|
size_t len = strlen(value);
|
||||||
|
if (len > (size_t)s) {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
strncpy_s(val, s, value, s);
|
||||||
|
#else
|
||||||
|
strncpy(val, value, s);
|
||||||
|
#endif
|
||||||
|
val[s-1] = '\n';
|
||||||
|
} else {
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
strcpy_s(val, s, value);
|
||||||
|
#else
|
||||||
|
strcpy(val, value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char *id, size_t index, std::string &value)
|
void postgres_result_reader::read_value(const char *id, size_t index, std::string &value)
|
||||||
{
|
{
|
||||||
|
auto *val = PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index));
|
||||||
|
if (strlen(val) != 0) {
|
||||||
|
value.assign(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char *id, size_t index, std::string &value, size_t s)
|
void postgres_result_reader::read_value(const char *id, size_t index, std::string &value, size_t s)
|
||||||
{
|
{
|
||||||
|
auto *val = PQgetvalue(result_, static_cast<int>(row_index_), static_cast<int>(index));
|
||||||
|
if (strlen(val) != 0) {
|
||||||
|
value.assign(val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void postgres_result_reader::read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type,
|
|
||||||
size_t size)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +38,6 @@ public:
|
||||||
void read_value(const char *id, size_t index, char *value, size_t size) override;
|
void read_value(const char *id, size_t index, char *value, size_t size) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value) override;
|
void read_value(const char *id, size_t index, std::string &value) override;
|
||||||
void read_value(const char *id, size_t index, std::string &value, size_t s) override;
|
void read_value(const char *id, size_t index, std::string &value, size_t s) override;
|
||||||
void read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rows result_;
|
rows result_;
|
||||||
|
|
|
||||||
|
|
@ -129,86 +129,4 @@ void sqlite_result_reader::read_value(const char *id, size_t index, std::string
|
||||||
value.assign(result_[row_index_][index]);
|
value.assign(result_[row_index_][index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template < typename Type >
|
|
||||||
void convert(const char *valstr, sql::any_type &value)
|
|
||||||
{
|
|
||||||
Type val{};
|
|
||||||
sql::to_value(val, valstr);
|
|
||||||
value = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sqlite_result_reader::read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case sql::data_type_t::type_char:
|
|
||||||
convert<char>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_short:
|
|
||||||
convert<short>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_int:
|
|
||||||
convert<int>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_long:
|
|
||||||
convert<long>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_long_long:
|
|
||||||
convert<long long>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_unsigned_char:
|
|
||||||
convert<unsigned char>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_unsigned_short:
|
|
||||||
convert<unsigned short>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_unsigned_int:
|
|
||||||
convert<unsigned int>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_unsigned_long:
|
|
||||||
convert<unsigned long>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_unsigned_long_long:
|
|
||||||
convert<unsigned long long>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_float:
|
|
||||||
convert<float>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_double:
|
|
||||||
convert<double>(result_[row_index_][index], value);
|
|
||||||
break;
|
|
||||||
case sql::data_type_t::type_bool: {
|
|
||||||
int val{};
|
|
||||||
sql::to_value(val, result_[row_index_][index]);
|
|
||||||
value = val > 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case sql::data_type_t::type_text:
|
|
||||||
case sql::data_type_t::type_varchar: {
|
|
||||||
value = std::string{result_[row_index_][index]};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case sql::data_type_t::type_char_pointer: {
|
|
||||||
value = result_[row_index_][index];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case sql::data_type_t::type_time:
|
|
||||||
case sql::data_type_t::type_date: {
|
|
||||||
value = std::string{result_[row_index_][index]};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case sql::data_type_t::type_null: {
|
|
||||||
value = nullptr_t{};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case sql::data_type_t::type_blob: {
|
|
||||||
throw std::logic_error("data type blob not supported");
|
|
||||||
}
|
|
||||||
case sql::data_type_t::type_unknown: {
|
|
||||||
value = std::string(result_[row_index_][index]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -33,7 +33,7 @@ public:
|
||||||
virtual void read_value(const char *id, size_t index, char *value, size_t s) = 0;
|
virtual void read_value(const char *id, size_t index, char *value, size_t s) = 0;
|
||||||
virtual void read_value(const char *id, size_t index, std::string &value) = 0;
|
virtual void read_value(const char *id, size_t index, std::string &value) = 0;
|
||||||
virtual void read_value(const char *id, size_t index, std::string &value, size_t s) = 0;
|
virtual void read_value(const char *id, size_t index, std::string &value, size_t s) = 0;
|
||||||
virtual void read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size) = 0;
|
virtual void read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ set(SQL_SOURCES
|
||||||
sql/fk_value_extractor.cpp
|
sql/fk_value_extractor.cpp
|
||||||
sql/table_repository.cpp
|
sql/table_repository.cpp
|
||||||
sql/any_type_to_visitor.cpp
|
sql/any_type_to_visitor.cpp
|
||||||
sql/query_result.cpp)
|
sql/query_result.cpp
|
||||||
|
sql/query_result_reader.cpp)
|
||||||
|
|
||||||
set(SQL_HEADER
|
set(SQL_HEADER
|
||||||
../include/matador/sql/dialect.hpp
|
../include/matador/sql/dialect.hpp
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include "matador/sql/query_result_reader.hpp"
|
||||||
|
#include "matador/sql/to_value.hpp"
|
||||||
|
|
||||||
|
namespace matador::sql {
|
||||||
|
|
||||||
|
template < typename Type >
|
||||||
|
void convert(const char *valstr, sql::any_type &value)
|
||||||
|
{
|
||||||
|
Type val{};
|
||||||
|
sql::to_value(val, valstr);
|
||||||
|
value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void query_result_reader::read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case sql::data_type_t::type_char:
|
||||||
|
convert<char>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_short:
|
||||||
|
convert<short>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_int:
|
||||||
|
convert<int>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_long:
|
||||||
|
convert<long>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_long_long:
|
||||||
|
convert<long long>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_unsigned_char:
|
||||||
|
convert<unsigned char>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_unsigned_short:
|
||||||
|
convert<unsigned short>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_unsigned_int:
|
||||||
|
convert<unsigned int>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_unsigned_long:
|
||||||
|
convert<unsigned long>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_unsigned_long_long:
|
||||||
|
convert<unsigned long long>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_float:
|
||||||
|
convert<float>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_double:
|
||||||
|
convert<double>(column(index), value);
|
||||||
|
break;
|
||||||
|
case sql::data_type_t::type_bool: {
|
||||||
|
int val{};
|
||||||
|
sql::to_value(val, column(index));
|
||||||
|
value = val > 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_text:
|
||||||
|
case sql::data_type_t::type_varchar: {
|
||||||
|
value = std::string{column(index)};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_char_pointer: {
|
||||||
|
value = column(index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_time:
|
||||||
|
case sql::data_type_t::type_date: {
|
||||||
|
value = std::string{column(index)};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_null: {
|
||||||
|
value = nullptr_t{};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_blob: {
|
||||||
|
throw std::logic_error("data type blob not supported");
|
||||||
|
}
|
||||||
|
case sql::data_type_t::type_unknown: {
|
||||||
|
value = std::string(column(index));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <catch2/generators/catch_generators.hpp>
|
||||||
|
|
||||||
#include <matador/sql/condition.hpp>
|
#include <matador/sql/condition.hpp>
|
||||||
#include <matador/sql/session.hpp>
|
#include <matador/sql/session.hpp>
|
||||||
|
|
@ -66,7 +67,11 @@ TEST_CASE("Create and drop table statement with foreign key", "[session record]"
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute insert record statement", "[session record]") {
|
TEST_CASE("Execute insert record statement", "[session record]") {
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
auto dns = GENERATE(as<std::string>{},
|
||||||
|
"sqlite://sqlite.db",
|
||||||
|
"postgres://test:test123@127.0.0.1:5432/matador_test" );
|
||||||
|
|
||||||
|
connection_pool<connection> pool(dns, 4);
|
||||||
session s(pool);
|
session s(pool);
|
||||||
|
|
||||||
auto res = s.create()
|
auto res = s.create()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue