diff --git a/Makefile b/Makefile index 323946f2..4df34261 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ SRCS = src/utility/copy.cpp \ OBJS = $(subst .cpp,.o, $(SRCS)) -REGRESS = basic +REGRESS = $(subst .sql,,$(subst sql/,,$(wildcard sql/*.sql))) PG_CONFIG ?= pg_config diff --git a/expected/basic.out b/expected/basic.out index cd677f0c..24bd681a 100644 --- a/expected/basic.out +++ b/expected/basic.out @@ -48,3 +48,4 @@ DEBUG: -- (DuckDB/PostgresHeapScanGlobalState) Running 4 threads -- SET quack.max_threads_per_query TO default; SET client_min_messages TO default; DROP TABLE t; +DROP EXTENSION quack; diff --git a/expected/search_path.out b/expected/search_path.out new file mode 100644 index 00000000..2016b763 --- /dev/null +++ b/expected/search_path.out @@ -0,0 +1,71 @@ +CREATE EXTENSION quack; +CREATE TABLE t(a INT); +INSERT INTO t SELECT g from generate_series(1,10) g; +SELECT count(*) FROM t; + count_star() +-------------- + 10 +(1 row) + +SELECT count(*) FROM public.t; + count_star() +-------------- + 10 +(1 row) + +-- Create schema `other` +CREATE SCHEMA other; +CREATE TABLE other.t(a INT); +INSERT INTO other.t SELECT g from generate_series(1,100) g; +SELECT count(*) FROM other.t; + count_star() +-------------- + 100 +(1 row) + +-- Test fully qualified table name combinations +SELECT count(*) FROM public.t, other.t; + count_star() +-------------- + 1000 +(1 row) + +SELECT count(*) FROM t, other.t; + count_star() +-------------- + 1000 +(1 row) + +SELECT count(*) FROM t,t; +ERROR: table name "t" specified more than once +-- search_path ORDER matters. +SET search_path TO other, public; +SELECT count(*) FROM t; + count_star() +-------------- + 100 +(1 row) + +SELECT count(*) FROM t, public.t; + count_star() +-------------- + 1000 +(1 row) + +-- No search_path +SET search_path TO ''; +SELECT count(*) FROM t, other.t; +ERROR: relation "t" does not exist +LINE 1: SELECT count(*) FROM t, other.t; + ^ +SELECT count(*) FROM public.t, other.t; + count_star() +-------------- + 1000 +(1 row) + +-- Cleanup +DROP TABLE other.t; +DROP SCHEMA other; +RESET search_path; +DROP EXTENSION quack; diff --git a/sql/basic.sql b/sql/basic.sql index 238ca93e..f1462b6b 100644 --- a/sql/basic.sql +++ b/sql/basic.sql @@ -17,4 +17,6 @@ SELECT a, COUNT(*) FROM t WHERE a > 5 GROUP BY a ORDER BY a; SET quack.max_threads_per_query TO default; SET client_min_messages TO default; -DROP TABLE t; \ No newline at end of file +DROP TABLE t; + +DROP EXTENSION quack; \ No newline at end of file diff --git a/sql/search_path.sql b/sql/search_path.sql new file mode 100644 index 00000000..a2caf06a --- /dev/null +++ b/sql/search_path.sql @@ -0,0 +1,34 @@ +CREATE EXTENSION quack; + +CREATE TABLE t(a INT); +INSERT INTO t SELECT g from generate_series(1,10) g; +SELECT count(*) FROM t; +SELECT count(*) FROM public.t; + +-- Create schema `other` +CREATE SCHEMA other; +CREATE TABLE other.t(a INT); +INSERT INTO other.t SELECT g from generate_series(1,100) g; +SELECT count(*) FROM other.t; + +-- Test fully qualified table name combinations +SELECT count(*) FROM public.t, other.t; +SELECT count(*) FROM t, other.t; +SELECT count(*) FROM t,t; + +-- search_path ORDER matters. +SET search_path TO other, public; +SELECT count(*) FROM t; +SELECT count(*) FROM t, public.t; + +-- No search_path +SET search_path TO ''; +SELECT count(*) FROM t, other.t; +SELECT count(*) FROM public.t, other.t; + +-- Cleanup +DROP TABLE other.t; +DROP SCHEMA other; +RESET search_path; + +DROP EXTENSION quack; \ No newline at end of file diff --git a/src/quack_heap_scan.cpp b/src/quack_heap_scan.cpp index d84c3075..39c11e80 100644 --- a/src/quack_heap_scan.cpp +++ b/src/quack_heap_scan.cpp @@ -5,8 +5,15 @@ #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/comparison_expression.hpp" #include "duckdb/parser/expression/columnref_expression.hpp" +#include "duckdb/parser/qualified_name.hpp" #include "duckdb/common/enums/expression_type.hpp" +extern "C" { +#include "postgres.h" +#include "catalog/namespace.h" +#include "utils/regproc.h" +} + #include "quack/quack_heap_scan.hpp" #include "quack/quack_types.hpp" @@ -139,6 +146,7 @@ PostgresHeapScanFunction::PostgresHeapScanFunc(duckdb::ClientContext &context, d static RangeTblEntry * FindMatchingHeapRelation(List *tables, const duckdb::string &to_find) { ListCell *lc; + foreach (lc, tables) { RangeTblEntry *table = (RangeTblEntry *)lfirst(lc); if (table->relid) { @@ -147,22 +155,22 @@ FindMatchingHeapRelation(List *tables, const duckdb::string &to_find) { elog(ERROR, "Relation with OID %u is not valid", table->relid); return nullptr; } - char *rel_name = RelationGetRelationName(rel); - auto table_name = std::string(rel_name); - if (duckdb::StringUtil::CIEquals(table_name, to_find)) { - /* Allow only heap tables */ - if (!rel->rd_amhandler || (GetTableAmRoutine(rel->rd_amhandler) != GetHeapamTableAmRoutine())) { - /* This doesn't have an access method handler, we cant read from this */ - RelationClose(rel); - return nullptr; - } else { - RelationClose(rel); - return table; - } + /* Allow only heap tables */ + if (!rel->rd_amhandler || (GetTableAmRoutine(rel->rd_amhandler) != GetHeapamTableAmRoutine())) { + /* This doesn't have an access method handler, we cant read from this */ + RelationClose(rel); + return nullptr; + } + RangeVar *tableRangeVar = makeRangeVarFromNameList(stringToQualifiedNameList(to_find.c_str(), NULL)); + Oid relOid = RangeVarGetRelid(tableRangeVar, AccessShareLock, true); + if (table->relid == relOid) { + RelationClose(rel); + return table; } RelationClose(rel); } } + return nullptr; } @@ -196,6 +204,7 @@ PostgresHeapReplacementScan(duckdb::ClientContext &context, const duckdb::string auto children = CreateFunctionArguments(table, GetActiveSnapshot()); auto table_function = duckdb::make_uniq(); table_function->function = duckdb::make_uniq("postgres_heap_scan", std::move(children)); + table_function->alias = table->alias ? table->alias->aliasname : table_name; return std::move(table_function); }