This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new 38c21c231 refactor(c/driver/postgresql): Use GetObjectsHelper from
framework to build objects (#2189)
38c21c231 is described below
commit 38c21c2311a59803559cb0091b3f34180c28b25f
Author: Dewey Dunnington <[email protected]>
AuthorDate: Fri Oct 18 02:35:09 2024 +0000
refactor(c/driver/postgresql): Use GetObjectsHelper from framework to build
objects (#2189)
This PR migrates the PostgreSQL driver to use the same
`GetObjectsHelper` as the SQLite driver (the one provided by the
framework). This involved a few updates to the helper (notably: ensure
the filter is passed to the `LoadXXX()` methods), and an update to the
result helper to make it easier to store iteration state along a result
as a member of the helper.
---
c/driver/framework/objects.cc | 8 +-
c/driver/framework/objects.h | 12 +-
c/driver/postgresql/connection.cc | 863 +++++++++++++++---------------------
c/driver/postgresql/result_helper.h | 45 +-
c/driver/sqlite/sqlite.cc | 21 +-
r/adbcpostgresql/configure | 4 +-
6 files changed, 424 insertions(+), 529 deletions(-)
diff --git a/c/driver/framework/objects.cc b/c/driver/framework/objects.cc
index eaf62351d..691f6e414 100644
--- a/c/driver/framework/objects.cc
+++ b/c/driver/framework/objects.cc
@@ -284,7 +284,7 @@ struct GetObjectsBuilder {
}
Status AppendCatalogs() {
- UNWRAP_STATUS(helper->LoadCatalogs());
+ UNWRAP_STATUS(helper->LoadCatalogs(catalog_filter));
while (true) {
UNWRAP_RESULT(auto maybe_catalog, helper->NextCatalog());
if (!maybe_catalog.has_value()) break;
@@ -302,7 +302,7 @@ struct GetObjectsBuilder {
}
Status AppendSchemas(std::string_view catalog) {
- UNWRAP_STATUS(helper->LoadSchemas(catalog));
+ UNWRAP_STATUS(helper->LoadSchemas(catalog, schema_filter));
while (true) {
UNWRAP_RESULT(auto maybe_schema, helper->NextSchema());
if (!maybe_schema.has_value()) break;
@@ -323,7 +323,7 @@ struct GetObjectsBuilder {
}
Status AppendTables(std::string_view catalog, std::string_view schema) {
- UNWRAP_STATUS(helper->LoadTables(catalog, schema));
+ UNWRAP_STATUS(helper->LoadTables(catalog, schema, table_filter,
table_types));
while (true) {
UNWRAP_RESULT(auto maybe_table, helper->NextTable());
if (!maybe_table.has_value()) break;
@@ -348,7 +348,7 @@ struct GetObjectsBuilder {
Status AppendColumns(std::string_view catalog, std::string_view schema,
std::string_view table) {
- UNWRAP_STATUS(helper->LoadColumns(catalog, schema, table));
+ UNWRAP_STATUS(helper->LoadColumns(catalog, schema, table, column_filter));
while (true) {
UNWRAP_RESULT(auto maybe_column, helper->NextColumn());
if (!maybe_column.has_value()) break;
diff --git a/c/driver/framework/objects.h b/c/driver/framework/objects.h
index a855265ca..3e74e7883 100644
--- a/c/driver/framework/objects.h
+++ b/c/driver/framework/objects.h
@@ -108,26 +108,30 @@ struct GetObjectsHelper {
return status::NotImplemented("GetObjects");
}
- virtual Status LoadCatalogs() {
+ virtual Status LoadCatalogs(std::optional<std::string_view> catalog_filter) {
return status::NotImplemented("GetObjects at depth = catalog");
};
virtual Result<std::optional<std::string_view>> NextCatalog() { return
std::nullopt; }
- virtual Status LoadSchemas(std::string_view catalog) {
+ virtual Status LoadSchemas(std::string_view catalog,
+ std::optional<std::string_view> schema_filter) {
return status::NotImplemented("GetObjects at depth = schema");
};
virtual Result<std::optional<std::string_view>> NextSchema() { return
std::nullopt; }
- virtual Status LoadTables(std::string_view catalog, std::string_view schema)
{
+ virtual Status LoadTables(std::string_view catalog, std::string_view schema,
+ std::optional<std::string_view> table_filter,
+ const std::vector<std::string_view>& table_types) {
return status::NotImplemented("GetObjects at depth = table");
};
virtual Result<std::optional<Table>> NextTable() { return std::nullopt; }
virtual Status LoadColumns(std::string_view catalog, std::string_view schema,
- std::string_view table) {
+ std::string_view table,
+ std::optional<std::string_view> column_filter) {
return status::NotImplemented("GetObjects at depth = column");
};
diff --git a/c/driver/postgresql/connection.cc
b/c/driver/postgresql/connection.cc
index ca88c0a4e..17732810f 100644
--- a/c/driver/postgresql/connection.cc
+++ b/c/driver/postgresql/connection.cc
@@ -22,8 +22,10 @@
#include <cmath>
#include <cstring>
#include <memory>
+#include <optional>
#include <sstream>
#include <string>
+#include <string_view>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -38,6 +40,9 @@
#include "error.h"
#include "result_helper.h"
+using adbc::driver::Result;
+using adbc::driver::Status;
+
namespace adbcpq {
namespace {
@@ -51,551 +56,374 @@ static const std::unordered_map<std::string, std::string>
kPgTableTypes = {
{"table", "r"}, {"view", "v"}, {"materialized_view", "m"},
{"toast_table", "t"}, {"foreign_table", "f"}, {"partitioned_table", "p"}};
-class PqGetObjectsHelper {
+static const char* kCatalogQueryAll = "SELECT datname FROM
pg_catalog.pg_database";
+
+// catalog_name is not a parameter here or on any other queries
+// because it will always be the currently connected database.
+static const char* kSchemaQueryAll =
+ "SELECT nspname FROM pg_catalog.pg_namespace WHERE "
+ "nspname !~ '^pg_' AND nspname <> 'information_schema'";
+
+// Parameterized on schema_name, relkind
+// Note that when binding relkind as a string it must look like {"r", "v", ...}
+// (i.e., double quotes). Binding a binary list<string> element also works.
+static const char* kTablesQueryAll =
+ "SELECT c.relname, CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN
'view' "
+ "WHEN 'm' THEN 'materialized view' WHEN 't' THEN 'TOAST table' "
+ "WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' END "
+ "AS reltype FROM pg_catalog.pg_class c "
+ "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
+ "WHERE pg_catalog.pg_table_is_visible(c.oid) AND n.nspname = $1 AND
c.relkind = "
+ "ANY($2)";
+
+// Parameterized on schema_name, table_name
+static const char* kColumnsQueryAll =
+ "SELECT attr.attname, attr.attnum, "
+ "pg_catalog.col_description(cls.oid, attr.attnum) "
+ "FROM pg_catalog.pg_attribute AS attr "
+ "INNER JOIN pg_catalog.pg_class AS cls ON attr.attrelid = cls.oid "
+ "INNER JOIN pg_catalog.pg_namespace AS nsp ON nsp.oid = cls.relnamespace "
+ "WHERE attr.attnum > 0 AND NOT attr.attisdropped "
+ "AND nsp.nspname LIKE $1 AND cls.relname LIKE $2";
+
+// Parameterized on schema_name, table_name
+static const char* kConstraintsQueryAll =
+ "WITH fk_unnest AS ( "
+ " SELECT "
+ " con.conname, "
+ " 'FOREIGN KEY' AS contype, "
+ " conrelid, "
+ " UNNEST(con.conkey) AS conkey, "
+ " confrelid, "
+ " UNNEST(con.confkey) AS confkey "
+ " FROM pg_catalog.pg_constraint AS con "
+ " INNER JOIN pg_catalog.pg_class AS cls ON cls.oid = conrelid "
+ " INNER JOIN pg_catalog.pg_namespace AS nsp ON nsp.oid =
cls.relnamespace "
+ " WHERE con.contype = 'f' AND nsp.nspname = $1 "
+ " AND cls.relname = $2 "
+ "), "
+ "fk_names AS ( "
+ " SELECT "
+ " fk_unnest.conname, "
+ " fk_unnest.contype, "
+ " fk_unnest.conkey, "
+ " fk_unnest.confkey, "
+ " attr.attname, "
+ " fnsp.nspname AS fschema, "
+ " fcls.relname AS ftable, "
+ " fattr.attname AS fattname "
+ " FROM fk_unnest "
+ " INNER JOIN pg_catalog.pg_class AS cls ON cls.oid = fk_unnest.conrelid
"
+ " INNER JOIN pg_catalog.pg_class AS fcls ON fcls.oid =
fk_unnest.confrelid "
+ " INNER JOIN pg_catalog.pg_namespace AS fnsp ON fnsp.oid =
fcls.relnamespace"
+ " INNER JOIN pg_catalog.pg_attribute AS attr ON attr.attnum = "
+ "fk_unnest.conkey "
+ " AND attr.attrelid = fk_unnest.conrelid "
+ " LEFT JOIN pg_catalog.pg_attribute AS fattr ON fattr.attnum = "
+ "fk_unnest.confkey "
+ " AND fattr.attrelid = fk_unnest.confrelid "
+ "), "
+ "fkeys AS ( "
+ " SELECT "
+ " conname, "
+ " contype, "
+ " ARRAY_AGG(attname ORDER BY conkey) AS colnames, "
+ " fschema, "
+ " ftable, "
+ " ARRAY_AGG(fattname ORDER BY confkey) AS fcolnames "
+ " FROM fk_names "
+ " GROUP BY "
+ " conname, "
+ " contype, "
+ " fschema, "
+ " ftable "
+ "), "
+ "other_constraints AS ( "
+ " SELECT con.conname, CASE con.contype WHEN 'c' THEN 'CHECK' WHEN 'u'
THEN "
+ " 'UNIQUE' WHEN 'p' THEN 'PRIMARY KEY' END AS contype, "
+ " ARRAY_AGG(attr.attname) AS colnames "
+ " FROM pg_catalog.pg_constraint AS con "
+ " CROSS JOIN UNNEST(conkey) AS conkeys "
+ " INNER JOIN pg_catalog.pg_class AS cls ON cls.oid = con.conrelid "
+ " INNER JOIN pg_catalog.pg_namespace AS nsp ON nsp.oid =
cls.relnamespace "
+ " INNER JOIN pg_catalog.pg_attribute AS attr ON attr.attnum = conkeys "
+ " AND cls.oid = attr.attrelid "
+ " WHERE con.contype IN ('c', 'u', 'p') AND nsp.nspname = $1 "
+ " AND cls.relname = $2 "
+ " GROUP BY conname, contype "
+ ") "
+ "SELECT "
+ " conname, contype, colnames, fschema, ftable, fcolnames "
+ "FROM fkeys "
+ "UNION ALL "
+ "SELECT "
+ " conname, contype, colnames, NULL, NULL, NULL "
+ "FROM other_constraints";
+
+class PostgresGetObjectsHelper : public adbc::driver::GetObjectsHelper {
public:
- PqGetObjectsHelper(PGconn* conn, int depth, const char* catalog, const char*
db_schema,
- const char* table_name, const char** table_types,
- const char* column_name, struct ArrowSchema* schema,
- struct ArrowArray* array, struct AdbcError* error)
- : conn_(conn),
- depth_(depth),
- catalog_(catalog),
- db_schema_(db_schema),
- table_name_(table_name),
- table_types_(table_types),
- column_name_(column_name),
- schema_(schema),
- array_(array),
- error_(error) {
- na_error_ = {0};
- }
-
- AdbcStatusCode GetObjects() {
- RAISE_ADBC(InitArrowArray());
-
- catalog_name_col_ = array_->children[0];
- catalog_db_schemas_col_ = array_->children[1];
- catalog_db_schemas_items_ = catalog_db_schemas_col_->children[0];
- db_schema_name_col_ = catalog_db_schemas_items_->children[0];
- db_schema_tables_col_ = catalog_db_schemas_items_->children[1];
- schema_table_items_ = db_schema_tables_col_->children[0];
- table_name_col_ = schema_table_items_->children[0];
- table_type_col_ = schema_table_items_->children[1];
-
- table_columns_col_ = schema_table_items_->children[2];
- table_columns_items_ = table_columns_col_->children[0];
- column_name_col_ = table_columns_items_->children[0];
- column_position_col_ = table_columns_items_->children[1];
- column_remarks_col_ = table_columns_items_->children[2];
-
- table_constraints_col_ = schema_table_items_->children[3];
- table_constraints_items_ = table_constraints_col_->children[0];
- constraint_name_col_ = table_constraints_items_->children[0];
- constraint_type_col_ = table_constraints_items_->children[1];
-
- constraint_column_names_col_ = table_constraints_items_->children[2];
- constraint_column_name_col_ = constraint_column_names_col_->children[0];
-
- constraint_column_usages_col_ = table_constraints_items_->children[3];
- constraint_column_usage_items_ =
constraint_column_usages_col_->children[0];
- fk_catalog_col_ = constraint_column_usage_items_->children[0];
- fk_db_schema_col_ = constraint_column_usage_items_->children[1];
- fk_table_col_ = constraint_column_usage_items_->children[2];
- fk_column_name_col_ = constraint_column_usage_items_->children[3];
-
- RAISE_ADBC(AppendCatalogs());
- RAISE_ADBC(FinishArrowArray());
- return ADBC_STATUS_OK;
- }
-
- private:
- AdbcStatusCode InitArrowArray() {
- RAISE_ADBC(adbc::driver::MakeGetObjectsSchema(schema_).ToAdbc(error_));
-
- CHECK_NA_DETAIL(INTERNAL, ArrowArrayInitFromSchema(array_, schema_,
&na_error_),
- &na_error_, error_);
-
- CHECK_NA(INTERNAL, ArrowArrayStartAppending(array_), error_);
- return ADBC_STATUS_OK;
+ explicit PostgresGetObjectsHelper(PGconn* conn)
+ : current_database_(PQdb(conn)),
+ all_catalogs_(conn, kCatalogQueryAll),
+ some_catalogs_(conn, CatalogQuery()),
+ all_schemas_(conn, kSchemaQueryAll),
+ some_schemas_(conn, SchemaQuery()),
+ all_tables_(conn, kTablesQueryAll),
+ some_tables_(conn, TablesQuery()),
+ all_columns_(conn, kColumnsQueryAll),
+ some_columns_(conn, ColumnsQuery()),
+ all_constraints_(conn, kConstraintsQueryAll),
+ some_constraints_(conn, ConstraintsQuery()) {}
+
+ Status Load(adbc::driver::GetObjectsDepth depth,
+ std::optional<std::string_view> catalog_filter,
+ std::optional<std::string_view> schema_filter,
+ std::optional<std::string_view> table_filter,
+ std::optional<std::string_view> column_filter,
+ const std::vector<std::string_view>& table_types) override {
+ return Status::Ok();
}
- AdbcStatusCode AppendSchemas(std::string db_name) {
- // postgres only allows you to list schemas for the currently connected db
- if (!strcmp(db_name.c_str(), PQdb(conn_))) {
- struct StringBuilder query;
- std::memset(&query, 0, sizeof(query));
- if (StringBuilderInit(&query, /*initial_size*/ 256)) {
- return ADBC_STATUS_INTERNAL;
- }
-
- const char* stmt =
- "SELECT nspname FROM pg_catalog.pg_namespace WHERE "
- "nspname !~ '^pg_' AND nspname <> 'information_schema'";
-
- if (StringBuilderAppend(&query, "%s", stmt)) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
-
- std::vector<std::string> params;
- if (db_schema_ != NULL) {
- if (StringBuilderAppend(&query, "%s", " AND nspname = $1")) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
- params.push_back(db_schema_);
- }
-
- auto result_helper = PqResultHelper{conn_, std::string(query.buffer)};
- StringBuilderReset(&query);
+ Status LoadCatalogs(std::optional<std::string_view> catalog_filter) override
{
+ if (catalog_filter.has_value()) {
+ UNWRAP_STATUS(some_catalogs_.Execute({std::string(*catalog_filter)}));
+ next_catalog_ = some_catalogs_.Row(-1);
+ } else {
+ UNWRAP_STATUS(all_catalogs_.Execute());
+ next_catalog_ = all_catalogs_.Row(-1);
+ }
- RAISE_STATUS(error_, result_helper.Execute(params));
+ return Status::Ok();
+ };
- for (PqResultRow row : result_helper) {
- const char* schema_name = row[0].data;
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(db_schema_name_col_,
ArrowCharView(schema_name)),
- error_);
- if (depth_ == ADBC_OBJECT_DEPTH_DB_SCHEMAS) {
- CHECK_NA(INTERNAL, ArrowArrayAppendNull(db_schema_tables_col_, 1),
error_);
- } else {
- RAISE_ADBC(AppendTables(std::string(schema_name)));
- }
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(catalog_db_schemas_items_),
error_);
- }
+ Result<std::optional<std::string_view>> NextCatalog() override {
+ next_catalog_ = next_catalog_.Next();
+ if (!next_catalog_.IsValid()) {
+ return std::nullopt;
}
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(catalog_db_schemas_col_),
error_);
- return ADBC_STATUS_OK;
+ return next_catalog_[0].value();
}
- AdbcStatusCode AppendCatalogs() {
- struct StringBuilder query;
- std::memset(&query, 0, sizeof(query));
- if (StringBuilderInit(&query, /*initial_size=*/256) != 0) return
ADBC_STATUS_INTERNAL;
-
- if (StringBuilderAppend(&query, "%s", "SELECT datname FROM
pg_catalog.pg_database")) {
- return ADBC_STATUS_INTERNAL;
+ Status LoadSchemas(std::string_view catalog,
+ std::optional<std::string_view> schema_filter) override {
+ // PostgreSQL can only list for the current database
+ if (catalog != current_database_) {
+ return Status::Ok();
}
- std::vector<std::string> params;
- if (catalog_ != NULL) {
- if (StringBuilderAppend(&query, "%s", " WHERE datname = $1")) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
- params.push_back(catalog_);
+ if (schema_filter.has_value()) {
+ UNWRAP_STATUS(some_schemas_.Execute({std::string(*schema_filter)}));
+ next_schema_ = some_schemas_.Row(-1);
+ } else {
+ UNWRAP_STATUS(all_schemas_.Execute());
+ next_schema_ = all_schemas_.Row(-1);
}
+ return Status::Ok();
+ };
- PqResultHelper result_helper = PqResultHelper{conn_,
std::string(query.buffer)};
- StringBuilderReset(&query);
-
- RAISE_STATUS(error_, result_helper.Execute(params));
-
- for (PqResultRow row : result_helper) {
- const char* db_name = row[0].data;
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(catalog_name_col_,
ArrowCharView(db_name)), error_);
- if (depth_ == ADBC_OBJECT_DEPTH_CATALOGS) {
- CHECK_NA(INTERNAL, ArrowArrayAppendNull(catalog_db_schemas_col_, 1),
error_);
- } else {
- RAISE_ADBC(AppendSchemas(std::string(db_name)));
- }
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(array_), error_);
+ Result<std::optional<std::string_view>> NextSchema() override {
+ next_schema_ = next_schema_.Next();
+ if (!next_schema_.IsValid()) {
+ return std::nullopt;
}
- return ADBC_STATUS_OK;
+ return next_schema_[0].value();
}
- AdbcStatusCode AppendTables(std::string schema_name) {
- struct StringBuilder query;
- std::memset(&query, 0, sizeof(query));
- if (StringBuilderInit(&query, /*initial_size*/ 512)) {
- return ADBC_STATUS_INTERNAL;
- }
+ Status LoadTables(std::string_view catalog, std::string_view schema,
+ std::optional<std::string_view> table_filter,
+ const std::vector<std::string_view>& table_types) override
{
+ std::string table_types_bind = TableTypesArrayLiteral(table_types);
- std::vector<std::string> params = {schema_name};
- const char* stmt =
- "SELECT c.relname, CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN
'view' "
- "WHEN 'm' THEN 'materialized view' WHEN 't' THEN 'TOAST table' "
- "WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'partitioned table' END "
- "AS reltype FROM pg_catalog.pg_class c "
- "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
- "WHERE c.relkind IN ('r','v','m','t','f','p') "
- "AND pg_catalog.pg_table_is_visible(c.oid) AND n.nspname = $1";
-
- if (StringBuilderAppend(&query, "%s", stmt)) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
+ if (table_filter.has_value()) {
+ UNWRAP_STATUS(some_tables_.Execute(
+ {std::string(schema), table_types_bind,
std::string(*table_filter)}));
+ next_table_ = some_tables_.Row(-1);
+ } else {
+ UNWRAP_STATUS(all_tables_.Execute({std::string(schema),
table_types_bind}));
+ next_table_ = all_tables_.Row(-1);
}
- if (table_name_ != nullptr) {
- if (StringBuilderAppend(&query, "%s", " AND c.relname LIKE $2")) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
+ return Status::Ok();
+ };
- params.push_back(std::string(table_name_));
+ Result<std::optional<Table>> NextTable() override {
+ next_table_ = next_table_.Next();
+ if (!next_table_.IsValid()) {
+ return std::nullopt;
}
- if (table_types_ != nullptr) {
- std::vector<std::string> table_type_filter;
- const char** table_types = table_types_;
- while (*table_types != NULL) {
- auto table_type_str = std::string(*table_types);
- auto search = kPgTableTypes.find(table_type_str);
- if (search != kPgTableTypes.end()) {
- table_type_filter.push_back(search->second);
- }
- table_types++;
- }
-
- if (!table_type_filter.empty()) {
- std::ostringstream oss;
- bool first = true;
- oss << "(";
- for (const auto& str : table_type_filter) {
- if (!first) {
- oss << ", ";
- }
- oss << "'" << str << "'";
- first = false;
- }
- oss << ")";
+ return Table{next_table_[0].value(), next_table_[1].value()};
+ }
- if (StringBuilderAppend(&query, "%s%s", " AND c.relkind IN ",
- oss.str().c_str())) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
- } else {
- // no matching table type means no records should come back
- if (StringBuilderAppend(&query, "%s", " AND false")) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
- }
+ Status LoadColumns(std::string_view catalog, std::string_view schema,
+ std::string_view table,
+ std::optional<std::string_view> column_filter) override {
+ if (column_filter.has_value()) {
+ UNWRAP_STATUS(some_columns_.Execute(
+ {std::string(schema), std::string(table),
std::string(*column_filter)}))
+ UNWRAP_STATUS(some_constraints_.Execute(
+ {std::string(schema), std::string(table),
std::string(*column_filter)}))
+ next_column_ = some_columns_.Row(-1);
+ next_constraint_ = some_constraints_.Row(-1);
+ } else {
+ UNWRAP_STATUS(all_columns_.Execute({std::string(schema),
std::string(table)}))
+ UNWRAP_STATUS(all_constraints_.Execute({std::string(schema),
std::string(table)}))
+ next_column_ = all_columns_.Row(-1);
+ next_constraint_ = all_constraints_.Row(-1);
}
- auto result_helper = PqResultHelper{conn_, query.buffer};
- StringBuilderReset(&query);
+ return Status::Ok();
+ };
- RAISE_STATUS(error_, result_helper.Execute(params));
- for (PqResultRow row : result_helper) {
- const char* table_name = row[0].data;
- const char* table_type = row[1].data;
+ Result<std::optional<Column>> NextColumn() override {
+ next_column_ = next_column_.Next();
+ if (!next_column_.IsValid()) {
+ return std::nullopt;
+ }
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(table_name_col_,
ArrowCharView(table_name)),
- error_);
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(table_type_col_,
ArrowCharView(table_type)),
- error_);
- if (depth_ == ADBC_OBJECT_DEPTH_TABLES) {
- CHECK_NA(INTERNAL, ArrowArrayAppendNull(table_columns_col_, 1),
error_);
- CHECK_NA(INTERNAL, ArrowArrayAppendNull(table_constraints_col_, 1),
error_);
- } else {
- auto table_name_s = std::string(table_name);
- RAISE_ADBC(AppendColumns(schema_name, table_name_s));
- RAISE_ADBC(AppendConstraints(schema_name, table_name_s));
- }
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(schema_table_items_), error_);
+ Column col;
+ col.column_name = next_column_[0].value();
+ UNWRAP_RESULT(col.ordinal_position, next_column_[1].ParseInteger());
+ if (!next_column_[2].is_null) {
+ col.remarks = next_column_[2].value();
}
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(db_schema_tables_col_), error_);
- return ADBC_STATUS_OK;
+ return col;
}
- AdbcStatusCode AppendColumns(std::string schema_name, std::string
table_name) {
- struct StringBuilder query;
- std::memset(&query, 0, sizeof(query));
- if (StringBuilderInit(&query, /*initial_size*/ 512)) {
- return ADBC_STATUS_INTERNAL;
- }
-
- std::vector<std::string> params = {schema_name, table_name};
- const char* stmt =
- "SELECT attr.attname, attr.attnum, "
- "pg_catalog.col_description(cls.oid, attr.attnum) "
- "FROM pg_catalog.pg_attribute AS attr "
- "INNER JOIN pg_catalog.pg_class AS cls ON attr.attrelid = cls.oid "
- "INNER JOIN pg_catalog.pg_namespace AS nsp ON nsp.oid =
cls.relnamespace "
- "WHERE attr.attnum > 0 AND NOT attr.attisdropped "
- "AND nsp.nspname LIKE $1 AND cls.relname LIKE $2";
-
- if (StringBuilderAppend(&query, "%s", stmt)) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
+ Result<std::optional<Constraint>> NextConstraint() override {
+ next_constraint_ = next_constraint_.Next();
+ if (!next_constraint_.IsValid()) {
+ return std::nullopt;
}
- if (column_name_ != NULL) {
- if (StringBuilderAppend(&query, "%s", " AND attr.attname LIKE $3")) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
+ Constraint out;
+ out.name = next_constraint_[0].data;
+ out.type = next_constraint_[1].data;
- params.push_back(std::string(column_name_));
+ UNWRAP_RESULT(constraint_fcolumn_names_,
next_constraint_[2].ParseTextArray());
+ std::vector<std::string_view> fcolumn_names_view;
+ for (const std::string& item : constraint_fcolumn_names_) {
+ fcolumn_names_view.push_back(item);
}
+ out.column_names = std::move(fcolumn_names_view);
- auto result_helper = PqResultHelper{conn_, query.buffer};
- StringBuilderReset(&query);
-
- RAISE_STATUS(error_, result_helper.Execute(params));
+ if (out.type == "FOREIGN KEY") {
+ assert(!next_constraint_[3].is_null);
+ assert(!next_constraint_[3].is_null);
+ assert(!next_constraint_[4].is_null);
+ assert(!next_constraint_[5].is_null);
- for (PqResultRow row : result_helper) {
- const char* column_name = row[0].data;
- const char* position = row[1].data;
+ out.usage = std::vector<ConstraintUsage>();
+ UNWRAP_RESULT(constraint_fkey_names_,
next_constraint_[5].ParseTextArray());
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(column_name_col_,
ArrowCharView(column_name)),
- error_);
- int ival = atol(position);
- CHECK_NA(INTERNAL,
- ArrowArrayAppendInt(column_position_col_,
static_cast<int64_t>(ival)),
- error_);
- if (row[2].is_null) {
- CHECK_NA(INTERNAL, ArrowArrayAppendNull(column_remarks_col_, 1),
error_);
- } else {
- const char* remarks = row[2].data;
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(column_remarks_col_,
ArrowCharView(remarks)),
- error_);
- }
+ for (const auto& item : constraint_fkey_names_) {
+ ConstraintUsage usage;
+ usage.catalog = current_database_;
+ usage.schema = next_constraint_[3].data;
+ usage.table = next_constraint_[4].data;
+ usage.column = item;
- // no xdbc_ values for now
- for (auto i = 3; i < 19; i++) {
- CHECK_NA(INTERNAL,
ArrowArrayAppendNull(table_columns_items_->children[i], 1),
- error_);
+ out.usage->push_back(usage);
}
-
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(table_columns_items_),
error_);
}
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(table_columns_col_), error_);
- return ADBC_STATUS_OK;
+ return out;
}
- // libpq PQexecParams can use either text or binary transfers
- // For now we are using text transfer internally, so arrays are sent
- // back like {element1, element2} within a const char*
- std::vector<std::string> PqTextArrayToVector(std::string text_array) {
- text_array.erase(0, 1);
- text_array.erase(text_array.size() - 1);
-
- std::vector<std::string> elements;
- std::stringstream ss(std::move(text_array));
- std::string tmp;
-
- while (getline(ss, tmp, ',')) {
- elements.push_back(std::move(tmp));
- }
-
- return elements;
+ private:
+ std::string current_database_;
+
+ // Ready-to-Execute() queries
+ PqResultHelper all_catalogs_;
+ PqResultHelper some_catalogs_;
+ PqResultHelper all_schemas_;
+ PqResultHelper some_schemas_;
+ PqResultHelper all_tables_;
+ PqResultHelper some_tables_;
+ PqResultHelper all_columns_;
+ PqResultHelper some_columns_;
+ PqResultHelper all_constraints_;
+ PqResultHelper some_constraints_;
+
+ // Iterator state for the catalogs/schema/table/column queries
+ PqResultRow next_catalog_;
+ PqResultRow next_schema_;
+ PqResultRow next_table_;
+ PqResultRow next_column_;
+ PqResultRow next_constraint_;
+
+ // Owning variants required because the framework versions of these
+ // are all based on string_view and the result helper can only parse arrays
+ // into std::vector<std::string>.
+ std::vector<std::string> constraint_fcolumn_names_;
+ std::vector<std::string> constraint_fkey_names_;
+
+ // Queries that are slightly modified versions of the generic queries that
allow
+ // the filter for that level to be passed through as a parameter. Defined
here
+ // because global strings should be const char* according to cpplint and
using
+ // the + operator to concatenate them is the most concise way to construct
them.
+
+ // Parameterized on catalog_name
+ static std::string CatalogQuery() {
+ return std::string(kCatalogQueryAll) + " WHERE datname = $1";
}
- AdbcStatusCode AppendConstraints(std::string schema_name, std::string
table_name) {
- struct StringBuilder query;
- std::memset(&query, 0, sizeof(query));
- if (StringBuilderInit(&query, /*initial_size*/ 4096)) {
- return ADBC_STATUS_INTERNAL;
- }
-
- std::vector<std::string> params = {schema_name, table_name};
- const char* stmt =
- "WITH fk_unnest AS ( "
- " SELECT "
- " con.conname, "
- " 'FOREIGN KEY' AS contype, "
- " conrelid, "
- " UNNEST(con.conkey) AS conkey, "
- " confrelid, "
- " UNNEST(con.confkey) AS confkey "
- " FROM pg_catalog.pg_constraint AS con "
- " INNER JOIN pg_catalog.pg_class AS cls ON cls.oid = conrelid "
- " INNER JOIN pg_catalog.pg_namespace AS nsp ON nsp.oid =
cls.relnamespace "
- " WHERE con.contype = 'f' AND nsp.nspname LIKE $1 "
- " AND cls.relname LIKE $2 "
- "), "
- "fk_names AS ( "
- " SELECT "
- " fk_unnest.conname, "
- " fk_unnest.contype, "
- " fk_unnest.conkey, "
- " fk_unnest.confkey, "
- " attr.attname, "
- " fnsp.nspname AS fschema, "
- " fcls.relname AS ftable, "
- " fattr.attname AS fattname "
- " FROM fk_unnest "
- " INNER JOIN pg_catalog.pg_class AS cls ON cls.oid =
fk_unnest.conrelid "
- " INNER JOIN pg_catalog.pg_class AS fcls ON fcls.oid =
fk_unnest.confrelid "
- " INNER JOIN pg_catalog.pg_namespace AS fnsp ON fnsp.oid =
fcls.relnamespace"
- " INNER JOIN pg_catalog.pg_attribute AS attr ON attr.attnum = "
- "fk_unnest.conkey "
- " AND attr.attrelid = fk_unnest.conrelid "
- " LEFT JOIN pg_catalog.pg_attribute AS fattr ON fattr.attnum = "
- "fk_unnest.confkey "
- " AND fattr.attrelid = fk_unnest.confrelid "
- "), "
- "fkeys AS ( "
- " SELECT "
- " conname, "
- " contype, "
- " ARRAY_AGG(attname ORDER BY conkey) AS colnames, "
- " fschema, "
- " ftable, "
- " ARRAY_AGG(fattname ORDER BY confkey) AS fcolnames "
- " FROM fk_names "
- " GROUP BY "
- " conname, "
- " contype, "
- " fschema, "
- " ftable "
- "), "
- "other_constraints AS ( "
- " SELECT con.conname, CASE con.contype WHEN 'c' THEN 'CHECK' WHEN
'u' THEN "
- " 'UNIQUE' WHEN 'p' THEN 'PRIMARY KEY' END AS contype, "
- " ARRAY_AGG(attr.attname) AS colnames "
- " FROM pg_catalog.pg_constraint AS con "
- " CROSS JOIN UNNEST(conkey) AS conkeys "
- " INNER JOIN pg_catalog.pg_class AS cls ON cls.oid = con.conrelid "
- " INNER JOIN pg_catalog.pg_namespace AS nsp ON nsp.oid =
cls.relnamespace "
- " INNER JOIN pg_catalog.pg_attribute AS attr ON attr.attnum =
conkeys "
- " AND cls.oid = attr.attrelid "
- " WHERE con.contype IN ('c', 'u', 'p') AND nsp.nspname LIKE $1 "
- " AND cls.relname LIKE $2 "
- " GROUP BY conname, contype "
- ") "
- "SELECT "
- " conname, contype, colnames, fschema, ftable, fcolnames "
- "FROM fkeys "
- "UNION ALL "
- "SELECT "
- " conname, contype, colnames, NULL, NULL, NULL "
- "FROM other_constraints";
-
- if (StringBuilderAppend(&query, "%s", stmt)) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
-
- if (column_name_ != NULL) {
- if (StringBuilderAppend(&query, "%s", " WHERE conname LIKE $3")) {
- StringBuilderReset(&query);
- return ADBC_STATUS_INTERNAL;
- }
-
- params.push_back(std::string(column_name_));
- }
+ // Parameterized on schema_name
+ static std::string SchemaQuery() {
+ return std::string(kSchemaQueryAll) + " AND nspname = $1";
+ }
- auto result_helper = PqResultHelper{conn_, query.buffer};
- StringBuilderReset(&query);
+ // Parameterized on schema_name, relkind, table_name
+ static std::string TablesQuery() {
+ return std::string(kTablesQueryAll) + " AND c.relname LIKE $3";
+ }
- RAISE_STATUS(error_, result_helper.Execute(params));
+ // Parameterized on schema_name, table_name, column_name
+ static std::string ColumnsQuery() {
+ return std::string(kColumnsQueryAll) + " AND attr.attname LIKE $3";
+ }
- for (PqResultRow row : result_helper) {
- const char* constraint_name = row[0].data;
- const char* constraint_type = row[1].data;
+ // Parameterized on schema_name, table_name, column_name
+ static std::string ConstraintsQuery() {
+ return std::string(kConstraintsQueryAll) + " WHERE conname LIKE $3";
+ }
- CHECK_NA(
- INTERNAL,
- ArrowArrayAppendString(constraint_name_col_,
ArrowCharView(constraint_name)),
- error_);
+ std::string TableTypesArrayLiteral(const std::vector<std::string_view>&
table_types) {
+ std::stringstream table_types_bind;
+ table_types_bind << "{";
+ int table_types_bind_len = 0;
- CHECK_NA(
- INTERNAL,
- ArrowArrayAppendString(constraint_type_col_,
ArrowCharView(constraint_type)),
- error_);
+ if (table_types.empty()) {
+ for (const auto& item : kPgTableTypes) {
+ if (table_types_bind_len > 0) {
+ table_types_bind << ", ";
+ }
- auto constraint_column_names =
PqTextArrayToVector(std::string(row[2].data));
- for (const auto& constraint_column_name : constraint_column_names) {
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(constraint_column_name_col_,
-
ArrowCharView(constraint_column_name.c_str())),
- error_);
+ table_types_bind << "\"" << item.second << "\"";
+ table_types_bind_len++;
}
- CHECK_NA(INTERNAL,
ArrowArrayFinishElement(constraint_column_names_col_), error_);
-
- if (!strcmp(constraint_type, "FOREIGN KEY")) {
- assert(!row[3].is_null);
- assert(!row[4].is_null);
- assert(!row[5].is_null);
-
- const char* constraint_ftable_schema = row[3].data;
- const char* constraint_ftable_name = row[4].data;
- auto constraint_fcolumn_names =
PqTextArrayToVector(std::string(row[5].data));
- for (const auto& constraint_fcolumn_name : constraint_fcolumn_names) {
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(fk_catalog_col_,
ArrowCharView(PQdb(conn_))),
- error_);
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(fk_db_schema_col_,
-
ArrowCharView(constraint_ftable_schema)),
- error_);
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(fk_table_col_,
-
ArrowCharView(constraint_ftable_name)),
- error_);
- CHECK_NA(INTERNAL,
- ArrowArrayAppendString(fk_column_name_col_,
-
ArrowCharView(constraint_fcolumn_name.c_str())),
- error_);
-
- CHECK_NA(INTERNAL,
ArrowArrayFinishElement(constraint_column_usage_items_),
- error_);
+ } else {
+ for (auto type : table_types) {
+ const auto maybe_item = kPgTableTypes.find(std::string(type));
+ if (maybe_item == kPgTableTypes.end()) {
+ continue;
}
- }
- CHECK_NA(INTERNAL,
ArrowArrayFinishElement(constraint_column_usages_col_), error_);
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(table_constraints_items_),
error_);
- }
- CHECK_NA(INTERNAL, ArrowArrayFinishElement(table_constraints_col_),
error_);
- return ADBC_STATUS_OK;
- }
+ if (table_types_bind_len > 0) {
+ table_types_bind << ", ";
+ }
- AdbcStatusCode FinishArrowArray() {
- CHECK_NA_DETAIL(INTERNAL, ArrowArrayFinishBuildingDefault(array_,
&na_error_),
- &na_error_, error_);
+ table_types_bind << "\"" << maybe_item->second << "\"";
+ table_types_bind_len++;
+ }
+ }
- return ADBC_STATUS_OK;
+ table_types_bind << "}";
+ return table_types_bind.str();
}
-
- PGconn* conn_ = nullptr;
- int depth_;
- const char* catalog_ = nullptr;
- const char* db_schema_ = nullptr;
- const char* table_name_ = nullptr;
- const char** table_types_ = nullptr;
- const char* column_name_ = nullptr;
- struct ArrowSchema* schema_ = nullptr;
- struct ArrowArray* array_ = nullptr;
- struct AdbcError* error_ = nullptr;
- struct ArrowError na_error_;
- struct ArrowArray* catalog_name_col_ = nullptr;
- struct ArrowArray* catalog_db_schemas_col_ = nullptr;
- struct ArrowArray* catalog_db_schemas_items_ = nullptr;
- struct ArrowArray* db_schema_name_col_ = nullptr;
- struct ArrowArray* db_schema_tables_col_ = nullptr;
- struct ArrowArray* schema_table_items_ = nullptr;
- struct ArrowArray* table_name_col_ = nullptr;
- struct ArrowArray* table_type_col_ = nullptr;
- struct ArrowArray* table_columns_col_ = nullptr;
- struct ArrowArray* table_columns_items_ = nullptr;
- struct ArrowArray* column_name_col_ = nullptr;
- struct ArrowArray* column_position_col_ = nullptr;
- struct ArrowArray* column_remarks_col_ = nullptr;
- struct ArrowArray* table_constraints_col_ = nullptr;
- struct ArrowArray* table_constraints_items_ = nullptr;
- struct ArrowArray* constraint_name_col_ = nullptr;
- struct ArrowArray* constraint_type_col_ = nullptr;
- struct ArrowArray* constraint_column_names_col_ = nullptr;
- struct ArrowArray* constraint_column_name_col_ = nullptr;
- struct ArrowArray* constraint_column_usages_col_ = nullptr;
- struct ArrowArray* constraint_column_usage_items_ = nullptr;
- struct ArrowArray* fk_catalog_col_ = nullptr;
- struct ArrowArray* fk_db_schema_col_ = nullptr;
- struct ArrowArray* fk_table_col_ = nullptr;
- struct ArrowArray* fk_column_name_col_ = nullptr;
};
// A notice processor that does nothing with notices. In the future we can log
@@ -689,26 +517,53 @@ AdbcStatusCode PostgresConnection::GetInfo(struct
AdbcConnection* connection,
}
AdbcStatusCode PostgresConnection::GetObjects(
- struct AdbcConnection* connection, int depth, const char* catalog,
- const char* db_schema, const char* table_name, const char** table_types,
+ struct AdbcConnection* connection, int c_depth, const char* catalog,
+ const char* db_schema, const char* table_name, const char** table_type,
const char* column_name, struct ArrowArrayStream* out, struct AdbcError*
error) {
- struct ArrowSchema schema;
- std::memset(&schema, 0, sizeof(schema));
- struct ArrowArray array;
- std::memset(&array, 0, sizeof(array));
+ PostgresGetObjectsHelper new_helper(conn_);
+
+ const auto catalog_filter =
+ catalog ? std::make_optional(std::string_view(catalog)) : std::nullopt;
+ const auto schema_filter =
+ db_schema ? std::make_optional(std::string_view(db_schema)) :
std::nullopt;
+ const auto table_filter =
+ table_name ? std::make_optional(std::string_view(table_name)) :
std::nullopt;
+ const auto column_filter =
+ column_name ? std::make_optional(std::string_view(column_name)) :
std::nullopt;
+ std::vector<std::string_view> table_type_filter;
+ while (table_type && *table_type) {
+ if (*table_type) {
+ table_type_filter.push_back(std::string_view(*table_type));
+ }
+ table_type++;
+ }
- PqGetObjectsHelper helper =
- PqGetObjectsHelper(conn_, depth, catalog, db_schema, table_name,
table_types,
- column_name, &schema, &array, error);
- AdbcStatusCode status = helper.GetObjects();
+ using adbc::driver::GetObjectsDepth;
- if (status != ADBC_STATUS_OK) {
- if (schema.release) schema.release(&schema);
- if (array.release) array.release(&array);
- return status;
+ GetObjectsDepth depth = GetObjectsDepth::kColumns;
+ switch (c_depth) {
+ case ADBC_OBJECT_DEPTH_CATALOGS:
+ depth = GetObjectsDepth::kCatalogs;
+ break;
+ case ADBC_OBJECT_DEPTH_COLUMNS:
+ depth = GetObjectsDepth::kColumns;
+ break;
+ case ADBC_OBJECT_DEPTH_DB_SCHEMAS:
+ depth = GetObjectsDepth::kSchemas;
+ break;
+ case ADBC_OBJECT_DEPTH_TABLES:
+ depth = GetObjectsDepth::kTables;
+ break;
+ default:
+ return Status::InvalidArgument("[libpq] GetObjects: invalid depth ",
c_depth)
+ .ToAdbc(error);
}
- adbc::driver::MakeArrayStream(&schema, &array, out);
+ auto status = BuildGetObjects(&new_helper, depth, catalog_filter,
schema_filter,
+ table_filter, column_filter,
table_type_filter, out);
+ RAISE_STATUS(error, new_helper.Close());
+ RAISE_STATUS(error, status);
+
return ADBC_STATUS_OK;
}
@@ -1250,7 +1105,11 @@ AdbcStatusCode PostgresConnection::SetOption(const char*
key, const char* value,
return ADBC_STATUS_OK;
} else if (std::strcmp(key, ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA) == 0) {
// PostgreSQL doesn't accept a parameter here
- PqResultHelper result_helper{conn_, std::string("SET search_path TO ") +
value};
+ char* value_esc = PQescapeIdentifier(conn_, value, strlen(value));
+ std::string query = std::string("SET search_path TO ") + value_esc;
+ PQfreemem(value_esc);
+
+ PqResultHelper result_helper{conn_, query};
RAISE_STATUS(error, result_helper.Execute());
return ADBC_STATUS_OK;
}
diff --git a/c/driver/postgresql/result_helper.h
b/c/driver/postgresql/result_helper.h
index 6dc7debf3..612573eda 100644
--- a/c/driver/postgresql/result_helper.h
+++ b/c/driver/postgresql/result_helper.h
@@ -18,6 +18,8 @@
#pragma once
#include <cassert>
+#include <charconv>
+#include <cstdint>
#include <memory>
#include <optional>
#include <string>
@@ -30,6 +32,7 @@
#include "copy/reader.h"
#include "driver/framework/status.h"
+using adbc::driver::Result;
using adbc::driver::Status;
namespace adbcpq {
@@ -49,6 +52,33 @@ struct PqRecord {
return result;
}
+ Result<int64_t> ParseInteger() const {
+ const char* last = data + len;
+ int64_t value = 0;
+ auto result = std::from_chars(data, last, value, 10);
+ if (result.ec == std::errc() && result.ptr == last) {
+ return value;
+ } else {
+ return Status::Internal("Can't parse '", data, "' as integer");
+ }
+ }
+
+ Result<std::vector<std::string>> ParseTextArray() {
+ std::string text_array(data, len);
+ text_array.erase(0, 1);
+ text_array.erase(text_array.size() - 1);
+
+ std::vector<std::string> elements;
+ std::stringstream ss(std::move(text_array));
+ std::string tmp;
+
+ while (getline(ss, tmp, ',')) {
+ elements.push_back(std::move(tmp));
+ }
+
+ return elements;
+ }
+
std::string_view value() { return std::string_view(data, len); }
};
@@ -56,12 +86,11 @@ struct PqRecord {
// row of a PGresult
class PqResultRow {
public:
- PqResultRow(PGresult* result, int row_num) : result_(result),
row_num_(row_num) {
- ncols_ = PQnfields(result);
- }
+ PqResultRow() : result_(nullptr), row_num_(-1) {}
+ PqResultRow(PGresult* result, int row_num) : result_(result),
row_num_(row_num) {}
- PqRecord operator[](const int& col_num) {
- assert(col_num < ncols_);
+ PqRecord operator[](const int& col_num) const {
+ assert(col_num < PQnfields(result_));
const char* data = PQgetvalue(result_, row_num_, col_num);
const int len = PQgetlength(result_, row_num_, col_num);
const bool is_null = PQgetisnull(result_, row_num_, col_num);
@@ -69,10 +98,13 @@ class PqResultRow {
return PqRecord{data, len, is_null};
}
+ bool IsValid() { return result_ && row_num_ >= 0 && row_num_ <
PQntuples(result_); }
+
+ PqResultRow Next() { return PqResultRow(result_, row_num_ + 1); }
+
private:
PGresult* result_ = nullptr;
int row_num_;
- int ncols_;
};
// Helper to manager the lifecycle of a PQResult. The query argument
@@ -135,6 +167,7 @@ class PqResultHelper {
return PQfname(result_, column_number);
}
Oid FieldType(int column_number) const { return PQftype(result_,
column_number); }
+ PqResultRow Row(int i) { return PqResultRow(result_, i); }
class iterator {
const PqResultHelper& outer_;
diff --git a/c/driver/sqlite/sqlite.cc b/c/driver/sqlite/sqlite.cc
index c6277fb62..a5186d00b 100644
--- a/c/driver/sqlite/sqlite.cc
+++ b/c/driver/sqlite/sqlite.cc
@@ -218,10 +218,6 @@ struct SqliteGetObjectsHelper : public
driver::GetObjectsHelper {
std::string query =
"SELECT DISTINCT name FROM pragma_database_list() WHERE name LIKE ?";
- this->table_filter = table_filter;
- this->column_filter = column_filter;
- this->table_types = table_types;
-
UNWRAP_STATUS(SqliteQuery::Scan(
conn, query,
[&](sqlite3_stmt* stmt) {
@@ -245,14 +241,17 @@ struct SqliteGetObjectsHelper : public
driver::GetObjectsHelper {
return status::Ok();
}
- Status LoadCatalogs() override { return status::Ok(); };
+ Status LoadCatalogs(std::optional<std::string_view> catalog_filter) override
{
+ return status::Ok();
+ };
Result<std::optional<std::string_view>> NextCatalog() override {
if (next_catalog >= catalogs.size()) return std::nullopt;
return catalogs[next_catalog++];
}
- Status LoadSchemas(std::string_view catalog) override {
+ Status LoadSchemas(std::string_view catalog,
+ std::optional<std::string_view> schema_filter) override {
next_schema = 0;
return status::Ok();
};
@@ -262,7 +261,9 @@ struct SqliteGetObjectsHelper : public
driver::GetObjectsHelper {
return schemas[next_schema++];
}
- Status LoadTables(std::string_view catalog, std::string_view schema)
override {
+ Status LoadTables(std::string_view catalog, std::string_view schema,
+ std::optional<std::string_view> table_filter,
+ const std::vector<std::string_view>& table_types) override
{
next_table = 0;
tables.clear();
if (!schema.empty()) return status::Ok();
@@ -305,7 +306,8 @@ struct SqliteGetObjectsHelper : public
driver::GetObjectsHelper {
}
Status LoadColumns(std::string_view catalog, std::string_view schema,
- std::string_view table) override {
+ std::string_view table,
+ std::optional<std::string_view> column_filter) override {
// XXX: pragma_table_info doesn't appear to work with bind parameters
// XXX: because we're saving the SqliteQuery, we also need to save the
string builder
columns_query.Reset();
@@ -482,9 +484,6 @@ struct SqliteGetObjectsHelper : public
driver::GetObjectsHelper {
};
sqlite3* conn = nullptr;
- std::optional<std::string_view> table_filter;
- std::optional<std::string_view> column_filter;
- std::vector<std::string_view> table_types;
std::vector<std::string> catalogs;
std::vector<std::string> schemas;
std::vector<std::pair<std::string, std::string>> tables;
diff --git a/r/adbcpostgresql/configure b/r/adbcpostgresql/configure
index 0e4eb0014..e2abe82d5 100755
--- a/r/adbcpostgresql/configure
+++ b/r/adbcpostgresql/configure
@@ -53,8 +53,8 @@ elif [ ! -z "$HAS_PKG_CONFIG" ]; then
PKG_LIBS="`pkg-config libpq --libs` $PKG_LIBS"
elif [ ! -z "$HAS_PG_CONFIG" ]; then
echo "Using pg_config to locate libpq headers/libs"
- PKG_CPPFLAGS="-I`pg_config --includedir` $PKG_CPPFLAGS"
- PKG_LIBS="-L`pg_config --libdir` -lpq $PKG_LIBS"
+ PKG_CPPFLAGS="-I`pg_config --includedir` `pg_config --cppflags`
$PKG_CPPFLAGS"
+ PKG_LIBS="-L`pg_config --libdir` -lpq `pg_config --ldflags` `pg_config
--libs` $PKG_LIBS"
else
echo "INCLUDE_DIR/LIB_DIR, pkg-config, and pg_config not found; trying
PKG_LIBS=-lpq"
PKG_LIBS="-lpq"