Skip to content

Add PostgresViewEntry #183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion create-postgres-tables.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
#!/bin/bash

# Set default value for the build type
BUILD_TYPE="release"
# If an argument is provided, use that as the build type instead
if [ $# -eq 1 ]; then
BUILD_TYPE=$1
fi

echo "
CREATE SCHEMA tpch;
CREATE SCHEMA tpcds;
CALL dbgen(sf=0.01, schema='tpch');
CALL dsdgen(sf=0.01, schema='tpcds');
EXPORT DATABASE '/tmp/postgresscannertmp';
" | \
./build/release/duckdb
./build/$BUILD_TYPE/duckdb

dropdb --if-exists postgresscanner
createdb postgresscanner
Expand Down
63 changes: 63 additions & 0 deletions src/include/storage/postgres_create_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
// DuckDB
//
// storage/postgres_create_info.hpp
//
//
//===----------------------------------------------------------------------===//

#pragma once

#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
#include "duckdb/parser/parsed_data/create_table_info.hpp"
#include "postgres_utils.hpp"

namespace duckdb {

enum class PostgresCreateInfoType : uint8_t { TABLE, VIEW };

struct PostgresCreateInfo {
public:
PostgresCreateInfo(PostgresCreateInfoType type) : type(type) {
}
virtual ~PostgresCreateInfo() {
}

public:
virtual CreateInfo &GetCreateInfo() = 0;
virtual const string &GetName() const = 0;
virtual void AddColumn(ColumnDefinition def, PostgresType pg_type, const string &pg_name) = 0;
virtual void GetColumnNamesAndTypes(vector<string> &names, vector<LogicalType> &types) = 0;
virtual idx_t PhysicalColumnCount() const = 0;
virtual void AddConstraint(unique_ptr<Constraint> constraint) = 0;
PostgresCreateInfoType GetType() const {
return type;
}

public:
template <class TARGET>
TARGET &Cast() {
if (type != TARGET::TYPE) {
throw InternalException("Failed to cast PostgresCreateInfo to type - PostgresCreateInfoType mismatch");
}
return reinterpret_cast<TARGET &>(*this);
}

template <class TARGET>
const TARGET &Cast() const {
if (type != TARGET::TYPE) {
throw InternalException("Failed to cast PostgresCreateInfo to type - PostgresCreateInfoType mismatch");
}
return reinterpret_cast<const TARGET &>(*this);
}

public:
idx_t approx_num_pages = 0;
vector<PostgresType> postgres_types;
vector<string> postgres_names;

protected:
PostgresCreateInfoType type;
};

} // namespace duckdb
49 changes: 40 additions & 9 deletions src/include/storage/postgres_table_entry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,69 @@

#include "duckdb/catalog/catalog_entry/table_catalog_entry.hpp"
#include "duckdb/parser/parsed_data/create_table_info.hpp"
#include "storage/postgres_create_info.hpp"
#include "postgres_utils.hpp"

namespace duckdb {

struct PostgresTableInfo {
PostgresTableInfo() {
struct PostgresTableInfo : public PostgresCreateInfo {
public:
static constexpr const PostgresCreateInfoType TYPE = PostgresCreateInfoType::TABLE;

public:
PostgresTableInfo() : PostgresCreateInfo(TYPE) {
create_info = make_uniq<CreateTableInfo>();
create_info->columns.SetAllowDuplicates(true);
}
PostgresTableInfo(const string &schema, const string &table) {
PostgresTableInfo(const string &schema, const string &table) : PostgresCreateInfo(TYPE) {
create_info = make_uniq<CreateTableInfo>(string(), schema, table);
create_info->columns.SetAllowDuplicates(true);
}
PostgresTableInfo(const SchemaCatalogEntry &schema, const string &table) {
PostgresTableInfo(const SchemaCatalogEntry &schema, const string &table) : PostgresCreateInfo(TYPE) {
create_info = make_uniq<CreateTableInfo>((SchemaCatalogEntry &)schema, table);
create_info->columns.SetAllowDuplicates(true);
}
~PostgresTableInfo() override {
}

const string &GetTableName() const {
public:
CreateInfo &GetCreateInfo() override {
return *create_info;
}

const string &GetName() const override {
return create_info->table;
}

void AddColumn(ColumnDefinition def, PostgresType pg_type, const string &pg_name) override {
postgres_types.push_back(std::move(pg_type));
D_ASSERT(!pg_name.empty());
postgres_names.push_back(pg_name);
create_info->columns.AddColumn(std::move(def));
}
void GetColumnNamesAndTypes(vector<string> &names, vector<LogicalType> &types) override {
for (auto &col : create_info->columns.Logical()) {
names.push_back(col.GetName());
types.push_back(col.GetType());
}
}
idx_t PhysicalColumnCount() const override {
return create_info->columns.PhysicalColumnCount();
}

void AddConstraint(unique_ptr<Constraint> constraint) override {
create_info->constraints.push_back(std::move(constraint));
}

public:
unique_ptr<CreateTableInfo> create_info;
vector<PostgresType> postgres_types;
vector<string> postgres_names;
idx_t approx_num_pages = 0;
};

class PostgresTableEntry : public TableCatalogEntry {
public:
PostgresTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateTableInfo &info);
PostgresTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, PostgresTableInfo &info);
~PostgresTableEntry() override;

public:
unique_ptr<BaseStatistics> GetStatistics(ClientContext &context, column_t column_id) override;
Expand All @@ -61,7 +92,7 @@ class PostgresTableEntry : public TableCatalogEntry {
vector<PostgresType> postgres_types;
//! Column names as they are within Postgres
//! We track these separately because of case sensitivity - Postgres allows e.g. the columns "ID" and "id" together
//! We would in this case remap them to "ID" and "id:1", while postgres_names store the original names
//! We would in this case remap them to "ID" and "id_1", while postgres_names store the original names
vector<string> postgres_names;
//! The approximate number of pages a table consumes in Postgres
idx_t approx_num_pages;
Expand Down
12 changes: 6 additions & 6 deletions src/include/storage/postgres_table_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ class PostgresTableSet : public PostgresInSchemaSet {
public:
optional_ptr<CatalogEntry> CreateTable(ClientContext &context, BoundCreateTableInfo &info);

static unique_ptr<PostgresTableInfo> GetTableInfo(PostgresTransaction &transaction, PostgresSchemaEntry &schema,
const string &table_name);
static unique_ptr<PostgresTableInfo> GetTableInfo(PostgresConnection &connection, const string &schema_name,
const string &table_name);
static unique_ptr<PostgresCreateInfo> GetTableInfo(PostgresTransaction &transaction, PostgresSchemaEntry &schema,
const string &table_name);
static unique_ptr<PostgresCreateInfo> GetTableInfo(PostgresConnection &connection, const string &schema_name,
const string &table_name);
optional_ptr<CatalogEntry> ReloadEntry(ClientContext &context, const string &table_name) override;

void AlterTable(ClientContext &context, AlterTableInfo &info);
Expand All @@ -46,11 +46,11 @@ class PostgresTableSet : public PostgresInSchemaSet {
void AlterTable(ClientContext &context, RemoveColumnInfo &info);

static void AddColumn(optional_ptr<PostgresTransaction> transaction, optional_ptr<PostgresSchemaEntry> schema,
PostgresResult &result, idx_t row, PostgresTableInfo &table_info);
PostgresResult &result, idx_t row, PostgresCreateInfo &pg_create_info);
static void AddConstraint(PostgresResult &result, idx_t row, PostgresTableInfo &table_info);
static void AddColumnOrConstraint(optional_ptr<PostgresTransaction> transaction,
optional_ptr<PostgresSchemaEntry> schema, PostgresResult &result, idx_t row,
PostgresTableInfo &table_info);
PostgresCreateInfo &table_info);

void CreateEntries(PostgresTransaction &transaction, PostgresResult &result, idx_t start, idx_t end);

Expand Down
91 changes: 91 additions & 0 deletions src/include/storage/postgres_view_entry.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//===----------------------------------------------------------------------===//
// DuckDB
//
// storage/postgres_view_entry.hpp
//
//
//===----------------------------------------------------------------------===//

#pragma once

#include "duckdb/catalog/catalog_entry/view_catalog_entry.hpp"
#include "duckdb/parser/parsed_data/create_view_info.hpp"
#include "storage/postgres_create_info.hpp"

namespace duckdb {

struct PostgresViewInfo : public PostgresCreateInfo {
public:
static constexpr const PostgresCreateInfoType TYPE = PostgresCreateInfoType::VIEW;

public:
PostgresViewInfo(const string &select_stmt) : PostgresCreateInfo(TYPE) {
create_info = make_uniq<CreateViewInfo>();
create_info->query = CreateViewInfo::ParseSelect(select_stmt);
// create_info->columns.SetAllowDuplicates(true);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this, the Table has a ColumnsList which provides this option, but no such option exists for views because we don't have a ColumnsList, we instead just store the types+names separately

}
PostgresViewInfo(const string &schema, const string &view, const string &select_stmt) : PostgresCreateInfo(TYPE) {
create_info = make_uniq<CreateViewInfo>(string(), schema, view);
create_info->query = CreateViewInfo::ParseSelect(select_stmt);
// create_info->columns.SetAllowDuplicates(true);
}
PostgresViewInfo(const SchemaCatalogEntry &schema, const string &view, const string &select_stmt)
: PostgresCreateInfo(TYPE) {
create_info = make_uniq<CreateViewInfo>((SchemaCatalogEntry &)schema, view);
create_info->query = CreateViewInfo::ParseSelect(select_stmt);
// create_info->columns.SetAllowDuplicates(true);
}
~PostgresViewInfo() override {
}

public:
const string &GetName() const override {
return create_info->view_name;
}

CreateInfo &GetCreateInfo() override {
return *create_info;
}

void AddColumn(ColumnDefinition def, PostgresType pg_type, const string &pg_name) override {
postgres_types.push_back(std::move(pg_type));
D_ASSERT(!pg_name.empty());
postgres_names.push_back(pg_name);
create_info->types.push_back(def.Type());
create_info->names.push_back(def.Name());
}

void GetColumnNamesAndTypes(vector<string> &names, vector<LogicalType> &types) override {
names = create_info->names;
types = create_info->types;
}
idx_t PhysicalColumnCount() const override {
D_ASSERT(create_info->types.size() == create_info->names.size());
return create_info->types.size();
}
void AddConstraint(unique_ptr<Constraint> constraint) override {
throw NotImplementedException("Can't create constraints on a VIEW entry");
}

public:
unique_ptr<CreateViewInfo> create_info;
};

class PostgresViewEntry : public ViewCatalogEntry {
public:
PostgresViewEntry(Catalog &catalog, SchemaCatalogEntry &schema, CreateViewInfo &info);
PostgresViewEntry(Catalog &catalog, SchemaCatalogEntry &schema, PostgresViewInfo &info);
~PostgresViewEntry() override;

public:
//! Postgres type annotations
vector<PostgresType> postgres_types;
//! Column names as they are within Postgres
//! We track these separately because of case sensitivity - Postgres allows e.g. the columns "ID" and "id" together
//! We would in this case remap them to "ID" and "id_1", while postgres_names store the original names
vector<string> postgres_names;
//! The approximate number of pages a table consumes in Postgres
idx_t approx_num_pages;
};

} // namespace duckdb
5 changes: 1 addition & 4 deletions src/postgres_scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,7 @@ static unique_ptr<FunctionData> PostgresBind(ClientContext &context, TableFuncti
auto info = PostgresTableSet::GetTableInfo(con, bind_data->schema_name, bind_data->table_name);

bind_data->postgres_types = info->postgres_types;
for (auto &col : info->create_info->columns.Logical()) {
names.push_back(col.GetName());
return_types.push_back(col.GetType());
}
info->GetColumnNamesAndTypes(names, return_types);
bind_data->names = info->postgres_names;
bind_data->types = return_types;
bind_data->can_use_main_thread = true;
Expand Down
4 changes: 3 additions & 1 deletion src/storage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ add_library(
postgres_transaction_manager.cpp
postgres_type_entry.cpp
postgres_type_set.cpp
postgres_update.cpp)
postgres_update.cpp
postgres_view_entry.cpp
)
set(ALL_OBJECT_FILES
${ALL_OBJECT_FILES} $<TARGET_OBJECTS:postgres_ext_storage>
PARENT_SCOPE)
1 change: 1 addition & 0 deletions src/storage/postgres_index_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ void PostgresIndexSet::LoadEntries(ClientContext &context) {
auto &result = index_result->GetResult();
for (idx_t row = index_result->start; row < index_result->end; row++) {
auto table_name = result.GetString(row, 1);
D_ASSERT(!table_name.empty());
auto index_name = result.GetString(row, 2);
CreateIndexInfo info;
info.schema = schema.name;
Expand Down
14 changes: 14 additions & 0 deletions src/storage/postgres_table_entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ PostgresTableEntry::PostgresTableEntry(Catalog &catalog, SchemaCatalogEntry &sch
col.TypeMutable() = PostgresUtils::RemoveAlias(col.GetType());
}
postgres_types.push_back(PostgresUtils::CreateEmptyPostgresType(col.GetType()));
D_ASSERT(!col.GetName().empty());
postgres_names.push_back(col.GetName());
}
approx_num_pages = 0;
Expand All @@ -23,6 +24,11 @@ PostgresTableEntry::PostgresTableEntry(Catalog &catalog, SchemaCatalogEntry &sch
PostgresTableEntry::PostgresTableEntry(Catalog &catalog, SchemaCatalogEntry &schema, PostgresTableInfo &info)
: TableCatalogEntry(catalog, schema, *info.create_info), postgres_types(std::move(info.postgres_types)),
postgres_names(std::move(info.postgres_names)) {
#ifdef DEBUG
for (auto &result_name : postgres_names) {
D_ASSERT(!result_name.empty());
}
#endif
D_ASSERT(postgres_types.size() == columns.LogicalColumnCount());
approx_num_pages = info.approx_num_pages;
}
Expand All @@ -48,6 +54,11 @@ TableFunction PostgresTableEntry::GetScanFunction(ClientContext &context, unique
result->types.push_back(col.GetType());
}
result->names = postgres_names;
#ifdef DEBUG
for (auto &result_name : result->names) {
D_ASSERT(!result_name.empty());
}
#endif
result->postgres_types = postgres_types;
result->read_only = transaction.IsReadOnly();
PostgresScanFunction::PrepareBind(pg_catalog.GetPostgresVersion(), context, *result, approx_num_pages);
Expand Down Expand Up @@ -120,4 +131,7 @@ PostgresCopyFormat PostgresTableEntry::GetCopyFormat(ClientContext &context) {
return PostgresCopyFormat::BINARY;
}

PostgresTableEntry::~PostgresTableEntry() {
}

} // namespace duckdb
Loading
Loading