From ec136db81ab9b92a32ad43d847fe528ef3590e84 Mon Sep 17 00:00:00 2001 From: Leo-XM-Zeng Date: Sat, 23 Nov 2024 14:11:31 +0800 Subject: [PATCH 1/7] When inserting multiple rows of data the entry with the default value is ignored unless it is specified --- src/vendor/pg_ruleutils_14.c | 4 +++ src/vendor/pg_ruleutils_15.c | 4 +++ src/vendor/pg_ruleutils_16.c | 4 +++ src/vendor/pg_ruleutils_17.c | 4 +++ test/regression/expected/temporary_tables.out | 29 ++++++++++++++++++- test/regression/sql/temporary_tables.sql | 13 ++++++++- 6 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/vendor/pg_ruleutils_14.c b/src/vendor/pg_ruleutils_14.c index 1f399c1d..3b56a960 100644 --- a/src/vendor/pg_ruleutils_14.c +++ b/src/vendor/pg_ruleutils_14.c @@ -6626,6 +6626,10 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ + /* When multi-VALUES, ignore an entry with a default value unless it is specified */ + if (values_rte != NULL && !(IsA(tle->expr, Var))) + continue; + appendStringInfoString(buf, sep); sep = ", "; diff --git a/src/vendor/pg_ruleutils_15.c b/src/vendor/pg_ruleutils_15.c index daa66aaa..7cbe8260 100644 --- a/src/vendor/pg_ruleutils_15.c +++ b/src/vendor/pg_ruleutils_15.c @@ -6707,6 +6707,10 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ + /* When multi-VALUES, ignore an entry with a default value unless it is specified */ + if (values_rte != NULL && !(IsA(tle->expr, Var))) + continue; + appendStringInfoString(buf, sep); sep = ", "; diff --git a/src/vendor/pg_ruleutils_16.c b/src/vendor/pg_ruleutils_16.c index e9346340..1d387356 100644 --- a/src/vendor/pg_ruleutils_16.c +++ b/src/vendor/pg_ruleutils_16.c @@ -6667,6 +6667,10 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ + /* When multi-VALUES, ignore an entry with a default value unless it is specified */ + if (values_rte != NULL && !(IsA(tle->expr, Var))) + continue; + appendStringInfoString(buf, sep); sep = ", "; diff --git a/src/vendor/pg_ruleutils_17.c b/src/vendor/pg_ruleutils_17.c index 01057d1f..bdf0af5b 100644 --- a/src/vendor/pg_ruleutils_17.c +++ b/src/vendor/pg_ruleutils_17.c @@ -6681,6 +6681,10 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ + /* When multi-VALUES, ignore an entry with a default value unless it is specified */ + if (values_rte != NULL && !(IsA(tle->expr, Var))) + continue; + appendStringInfoString(buf, sep); sep = ", "; diff --git a/test/regression/expected/temporary_tables.out b/test/regression/expected/temporary_tables.out index 3fdcadc2..3c981fd4 100644 --- a/test/regression/expected/temporary_tables.out +++ b/test/regression/expected/temporary_tables.out @@ -246,4 +246,31 @@ pg_temp main CREATE TABLE webpages(column00 INTEGER, column01 VARCHAR, column02 (1 row) -DROP TABLE webpages, t, t_heap, t_heap2; +CREATE TEMP TABLE ta (a int DEFAULT 3, b int) USING duckdb; +INSERT INTO ta (b) VALUES (123), (456); +INSERT INTO ta (a, b) VALUES (123, 456), (456, 123); +SELECT * FROM ta; + a | b +-----+----- + 3 | 123 + 3 | 456 + 123 | 456 + 456 | 123 +(4 rows) + +CREATE TEMP TABLE tb (a int DEFAULT 3, b int, c varchar DEFAULT 'pg_duckdb') USING duckdb; +INSERT INTO tb (a) VALUES (123), (456); +INSERT INTO tb (b) VALUES (123), (456); +INSERT INTO tb (c) VALUES ('ta'), ('tb'); +SELECT * FROM tb; + a | b | c +-----+-----+----------- + 123 | | pg_duckdb + 456 | | pg_duckdb + 3 | 123 | pg_duckdb + 3 | 456 | pg_duckdb + 3 | | ta + 3 | | tb +(6 rows) + +DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; diff --git a/test/regression/sql/temporary_tables.sql b/test/regression/sql/temporary_tables.sql index a80065d1..478b14f0 100644 --- a/test/regression/sql/temporary_tables.sql +++ b/test/regression/sql/temporary_tables.sql @@ -163,4 +163,15 @@ SELECT * FROM t_heap2; SELECT duckdb.raw_query($$ SELECT database_name, schema_name, sql FROM duckdb_tables() $$); -DROP TABLE webpages, t, t_heap, t_heap2; +CREATE TEMP TABLE ta (a int DEFAULT 3, b int) USING duckdb; +INSERT INTO ta (b) VALUES (123), (456); +INSERT INTO ta (a, b) VALUES (123, 456), (456, 123); +SELECT * FROM ta; + +CREATE TEMP TABLE tb (a int DEFAULT 3, b int, c varchar DEFAULT 'pg_duckdb') USING duckdb; +INSERT INTO tb (a) VALUES (123), (456); +INSERT INTO tb (b) VALUES (123), (456); +INSERT INTO tb (c) VALUES ('ta'), ('tb'); +SELECT * FROM tb; + +DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; From 546fe1e62f6d142de7984240b799b7fcf1dd946b Mon Sep 17 00:00:00 2001 From: Leo-XM-Zeng Date: Sun, 24 Nov 2024 00:55:15 +0800 Subject: [PATCH 2/7] Narrow the processing of "INSERT multi-VALUES" --- src/vendor/pg_ruleutils_14.c | 2 +- src/vendor/pg_ruleutils_15.c | 2 +- src/vendor/pg_ruleutils_16.c | 2 +- src/vendor/pg_ruleutils_17.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vendor/pg_ruleutils_14.c b/src/vendor/pg_ruleutils_14.c index 4e6019ed..6976917a 100644 --- a/src/vendor/pg_ruleutils_14.c +++ b/src/vendor/pg_ruleutils_14.c @@ -6634,7 +6634,7 @@ get_insert_query_def(Query *query, deparse_context *context, continue; /* ignore junk entries */ /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte != NULL && !(IsA(tle->expr, Var))) + if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) continue; appendStringInfoString(buf, sep); diff --git a/src/vendor/pg_ruleutils_15.c b/src/vendor/pg_ruleutils_15.c index 733f60a8..2df9f66a 100644 --- a/src/vendor/pg_ruleutils_15.c +++ b/src/vendor/pg_ruleutils_15.c @@ -6715,7 +6715,7 @@ get_insert_query_def(Query *query, deparse_context *context, continue; /* ignore junk entries */ /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte != NULL && !(IsA(tle->expr, Var))) + if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) continue; appendStringInfoString(buf, sep); diff --git a/src/vendor/pg_ruleutils_16.c b/src/vendor/pg_ruleutils_16.c index 5efbfdac..7414af74 100644 --- a/src/vendor/pg_ruleutils_16.c +++ b/src/vendor/pg_ruleutils_16.c @@ -6675,7 +6675,7 @@ get_insert_query_def(Query *query, deparse_context *context, continue; /* ignore junk entries */ /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte != NULL && !(IsA(tle->expr, Var))) + if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) continue; appendStringInfoString(buf, sep); diff --git a/src/vendor/pg_ruleutils_17.c b/src/vendor/pg_ruleutils_17.c index ccef4497..8c740531 100644 --- a/src/vendor/pg_ruleutils_17.c +++ b/src/vendor/pg_ruleutils_17.c @@ -6689,7 +6689,7 @@ get_insert_query_def(Query *query, deparse_context *context, continue; /* ignore junk entries */ /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte != NULL && !(IsA(tle->expr, Var))) + if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) continue; appendStringInfoString(buf, sep); From 7a217d9424888abfed19446f67ac9bce59e81e17 Mon Sep 17 00:00:00 2001 From: Leo-XM-Zeng Date: Thu, 28 Nov 2024 01:26:13 +0800 Subject: [PATCH 3/7] More details are needed to complete the functionality --- src/vendor/pg_ruleutils_14.c | 7 +++- src/vendor/pg_ruleutils_15.c | 7 +++- src/vendor/pg_ruleutils_16.c | 7 +++- src/vendor/pg_ruleutils_17.c | 7 +++- test/regression/expected/temporary_tables.out | 38 +++++++++++++++++++ test/regression/sql/temporary_tables.sql | 18 +++++++++ 6 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/vendor/pg_ruleutils_14.c b/src/vendor/pg_ruleutils_14.c index 59850997..49010f82 100644 --- a/src/vendor/pg_ruleutils_14.c +++ b/src/vendor/pg_ruleutils_14.c @@ -6637,8 +6637,11 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ - /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) + /* + * If it's an INSERT ... SELECT or multi-row VALUES, the entry + * with the default value is ignored unless it is specified + */ + if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) continue; appendStringInfoString(buf, sep); diff --git a/src/vendor/pg_ruleutils_15.c b/src/vendor/pg_ruleutils_15.c index e3291587..84915d62 100644 --- a/src/vendor/pg_ruleutils_15.c +++ b/src/vendor/pg_ruleutils_15.c @@ -6718,8 +6718,11 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ - /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) + /* + * If it's an INSERT ... SELECT or multi-row VALUES, the entry + * with the default value is ignored unless it is specified + */ + if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) continue; appendStringInfoString(buf, sep); diff --git a/src/vendor/pg_ruleutils_16.c b/src/vendor/pg_ruleutils_16.c index 68a0acf8..6700d5f9 100644 --- a/src/vendor/pg_ruleutils_16.c +++ b/src/vendor/pg_ruleutils_16.c @@ -6678,8 +6678,11 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ - /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) + /* + * If it's an INSERT ... SELECT or multi-row VALUES, the entry + * with the default value is ignored unless it is specified + */ + if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) continue; appendStringInfoString(buf, sep); diff --git a/src/vendor/pg_ruleutils_17.c b/src/vendor/pg_ruleutils_17.c index d8f55793..302da814 100644 --- a/src/vendor/pg_ruleutils_17.c +++ b/src/vendor/pg_ruleutils_17.c @@ -6692,8 +6692,11 @@ get_insert_query_def(Query *query, deparse_context *context, if (tle->resjunk) continue; /* ignore junk entries */ - /* When multi-VALUES, ignore an entry with a default value unless it is specified */ - if (values_rte && (IsA(tle->expr, Const) || IsA(tle->expr, FuncExpr))) + /* + * If it's an INSERT ... SELECT or multi-row VALUES, the entry + * with the default value is ignored unless it is specified + */ + if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) continue; appendStringInfoString(buf, sep); diff --git a/test/regression/expected/temporary_tables.out b/test/regression/expected/temporary_tables.out index c2840a27..ec173f19 100644 --- a/test/regression/expected/temporary_tables.out +++ b/test/regression/expected/temporary_tables.out @@ -246,6 +246,7 @@ pg_temp main CREATE TABLE webpages(column00 INTEGER, column01 VARCHAR, column02 (1 row) +-- multi-VALUES CREATE TEMP TABLE ta (a int DEFAULT 3, b int) USING duckdb; INSERT INTO ta (b) VALUES (123), (456); INSERT INTO ta (a, b) VALUES (123, 456), (456, 123); @@ -273,4 +274,41 @@ SELECT * FROM tb; 3 | | tb (6 rows) +-- INSERT ... SELECT +TRUNCATE TABLE ta; +INSERT INTO ta (a) SELECT 789; +INSERT INTO ta (b) SELECT 789; +INSERT INTO ta (a) SELECT * FROM t_heap; +INSERT INTO ta (b) SELECT * FROM t_heap; +SELECT * FROM ta; + a | b +-----+----- + 789 | + 3 | 789 + 1 | + 3 | 1 +(4 rows) + +INSERT INTO ta (a) SELECT generate_series(1, 3); -- no support +ERROR: (PGDuckDB/Duckdb_ExecCustomScan) Conversion Error: Unimplemented type for cast (BIGINT[] -> INTEGER) +LINE 1: INSERT INTO pg_temp.main.ta (a) SELECT generate_series(1, 3) AS generate_serie... + ^ +TRUNCATE TABLE tb; +INSERT INTO tb (a) SELECT 789; +INSERT INTO tb (b) SELECT 789; +INSERT INTO tb (a) SELECT * FROM t_heap; +INSERT INTO tb (b) SELECT * FROM t_heap; +SELECT * FROM tb; + a | b | c +-----+-----+----------- + 789 | | pg_duckdb + 3 | 789 | pg_duckdb + 1 | | pg_duckdb + 3 | 1 | pg_duckdb +(4 rows) + +INSERT INTO tb (c) SELECT 'ta'; -- no support +ERROR: (PGDuckDB/CreatePlan) Prepared query returned an error: 'Parser Error: syntax error at or near ")" +LINE 1: INSERT INTO pg_temp.main.tb () SELECT 'ta' + ^ DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; diff --git a/test/regression/sql/temporary_tables.sql b/test/regression/sql/temporary_tables.sql index f230395a..73a4110e 100644 --- a/test/regression/sql/temporary_tables.sql +++ b/test/regression/sql/temporary_tables.sql @@ -164,6 +164,7 @@ SELECT * FROM t_heap2; SELECT duckdb.raw_query($$ SELECT database_name, schema_name, sql FROM duckdb_tables() $$); +-- multi-VALUES CREATE TEMP TABLE ta (a int DEFAULT 3, b int) USING duckdb; INSERT INTO ta (b) VALUES (123), (456); INSERT INTO ta (a, b) VALUES (123, 456), (456, 123); @@ -175,4 +176,21 @@ INSERT INTO tb (b) VALUES (123), (456); INSERT INTO tb (c) VALUES ('ta'), ('tb'); SELECT * FROM tb; +-- INSERT ... SELECT +TRUNCATE TABLE ta; +INSERT INTO ta (a) SELECT 789; +INSERT INTO ta (b) SELECT 789; +INSERT INTO ta (a) SELECT * FROM t_heap; +INSERT INTO ta (b) SELECT * FROM t_heap; +SELECT * FROM ta; +INSERT INTO ta (a) SELECT generate_series(1, 3); -- no support + +TRUNCATE TABLE tb; +INSERT INTO tb (a) SELECT 789; +INSERT INTO tb (b) SELECT 789; +INSERT INTO tb (a) SELECT * FROM t_heap; +INSERT INTO tb (b) SELECT * FROM t_heap; +SELECT * FROM tb; +INSERT INTO tb (c) SELECT 'ta'; -- no support + DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; From b76aa3f38027d2ba43d9efbcbf01293fb82d2a3c Mon Sep 17 00:00:00 2001 From: Leo-XM-Zeng Date: Tue, 3 Dec 2024 11:25:11 +0800 Subject: [PATCH 4/7] Enhanced INSERT... SELECT --- src/vendor/pg_ruleutils_14.c | 17 ++++++++++-- src/vendor/pg_ruleutils_15.c | 17 ++++++++++-- src/vendor/pg_ruleutils_16.c | 17 ++++++++++-- src/vendor/pg_ruleutils_17.c | 17 ++++++++++-- test/regression/expected/temporary_tables.out | 26 ++++++++++++++++--- test/regression/sql/temporary_tables.sql | 12 ++++++++- 6 files changed, 93 insertions(+), 13 deletions(-) diff --git a/src/vendor/pg_ruleutils_14.c b/src/vendor/pg_ruleutils_14.c index 49010f82..c00eeb2f 100644 --- a/src/vendor/pg_ruleutils_14.c +++ b/src/vendor/pg_ruleutils_14.c @@ -6641,8 +6641,21 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) - continue; + if (values_rte) + { + if (!(IsA(tle->expr, Var))) + continue; + } + else if (select_rte) + { + /* + * If it's INSERT... SELECT needs to make more careful decisions about + * Const structures. If location is -1, it comes from the DEFAULT clause + */ + if (IsA(tle->expr, Const) && + ((Const *) tle->expr)->location == -1) + continue; + } appendStringInfoString(buf, sep); sep = ", "; diff --git a/src/vendor/pg_ruleutils_15.c b/src/vendor/pg_ruleutils_15.c index 84915d62..897c94d0 100644 --- a/src/vendor/pg_ruleutils_15.c +++ b/src/vendor/pg_ruleutils_15.c @@ -6722,8 +6722,21 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) - continue; + if (values_rte) + { + if (!(IsA(tle->expr, Var))) + continue; + } + else if (select_rte) + { + /* + * If it's INSERT... SELECT needs to make more careful decisions about + * Const structures. If location is -1, it comes from the DEFAULT clause + */ + if (IsA(tle->expr, Const) && + ((Const *) tle->expr)->location == -1) + continue; + } appendStringInfoString(buf, sep); sep = ", "; diff --git a/src/vendor/pg_ruleutils_16.c b/src/vendor/pg_ruleutils_16.c index 6700d5f9..a7dc97f9 100644 --- a/src/vendor/pg_ruleutils_16.c +++ b/src/vendor/pg_ruleutils_16.c @@ -6682,8 +6682,21 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) - continue; + if (values_rte) + { + if (!(IsA(tle->expr, Var))) + continue; + } + else if (select_rte) + { + /* + * If it's INSERT... SELECT needs to make more careful decisions about + * Const structures. If location is -1, it comes from the DEFAULT clause + */ + if (IsA(tle->expr, Const) && + ((Const *) tle->expr)->location == -1) + continue; + } appendStringInfoString(buf, sep); sep = ", "; diff --git a/src/vendor/pg_ruleutils_17.c b/src/vendor/pg_ruleutils_17.c index 302da814..480a9ba2 100644 --- a/src/vendor/pg_ruleutils_17.c +++ b/src/vendor/pg_ruleutils_17.c @@ -6696,8 +6696,21 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if ((select_rte || values_rte) && !(IsA(tle->expr, Var))) - continue; + if (values_rte) + { + if (!(IsA(tle->expr, Var))) + continue; + } + else if (select_rte) + { + /* + * If it's INSERT... SELECT needs to make more careful decisions about + * Const structures. If location is -1, it comes from the DEFAULT clause + */ + if (IsA(tle->expr, Const) && + ((Const *) tle->expr)->location == -1) + continue; + } appendStringInfoString(buf, sep); sep = ", "; diff --git a/test/regression/expected/temporary_tables.out b/test/regression/expected/temporary_tables.out index ec173f19..e97adf91 100644 --- a/test/regression/expected/temporary_tables.out +++ b/test/regression/expected/temporary_tables.out @@ -307,8 +307,26 @@ SELECT * FROM tb; 3 | 1 | pg_duckdb (4 rows) -INSERT INTO tb (c) SELECT 'ta'; -- no support -ERROR: (PGDuckDB/CreatePlan) Prepared query returned an error: 'Parser Error: syntax error at or near ")" -LINE 1: INSERT INTO pg_temp.main.tb () SELECT 'ta' - ^ +TRUNCATE TABLE tb; +INSERT INTO tb (c) SELECT 'ta'; +INSERT INTO tb (c) SELECT 'ta' || 'tb'; +INSERT INTO tb (a) SELECT (2)::numeric; +INSERT INTO tb (b) SELECT (3)::numeric; +INSERT INTO tb (c) SELECT t.a FROM (SELECT 'ta' || 'tb' AS a) t; +INSERT INTO tb (b, c) SELECT t.b, t.c FROM (SELECT (3)::numeric AS b, 'ta' || 'tb' AS c) t; +INSERT INTO tb (a, b, c) SELECT 1, 2, 'tb'; +INSERT INTO tb SELECT * FROM (SELECT (3)::numeric AS a, (3)::numeric AS b, 'ta' || 'tb' AS c) t; +SELECT * FROM tb; + a | b | c +---+---+----------- + 3 | | ta + 3 | | tatb + 2 | | pg_duckdb + 3 | 3 | pg_duckdb + 3 | | tatb + 3 | 3 | tatb + 1 | 2 | tb + 3 | 3 | tatb +(8 rows) + DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; diff --git a/test/regression/sql/temporary_tables.sql b/test/regression/sql/temporary_tables.sql index 73a4110e..074bb0cc 100644 --- a/test/regression/sql/temporary_tables.sql +++ b/test/regression/sql/temporary_tables.sql @@ -191,6 +191,16 @@ INSERT INTO tb (b) SELECT 789; INSERT INTO tb (a) SELECT * FROM t_heap; INSERT INTO tb (b) SELECT * FROM t_heap; SELECT * FROM tb; -INSERT INTO tb (c) SELECT 'ta'; -- no support + +TRUNCATE TABLE tb; +INSERT INTO tb (c) SELECT 'ta'; +INSERT INTO tb (c) SELECT 'ta' || 'tb'; +INSERT INTO tb (a) SELECT (2)::numeric; +INSERT INTO tb (b) SELECT (3)::numeric; +INSERT INTO tb (c) SELECT t.a FROM (SELECT 'ta' || 'tb' AS a) t; +INSERT INTO tb (b, c) SELECT t.b, t.c FROM (SELECT (3)::numeric AS b, 'ta' || 'tb' AS c) t; +INSERT INTO tb (a, b, c) SELECT 1, 2, 'tb'; +INSERT INTO tb SELECT * FROM (SELECT (3)::numeric AS a, (3)::numeric AS b, 'ta' || 'tb' AS c) t; +SELECT * FROM tb; DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; From 0bd3b209c8f67364d577a98bf392f2d193935e6b Mon Sep 17 00:00:00 2001 From: Leo-XM-Zeng Date: Tue, 3 Dec 2024 20:38:51 +0800 Subject: [PATCH 5/7] JelteF is right that we must search recursively for Const nodes and Var nodes to handle the more complex DEFAULT clause. --- include/pgduckdb/pgduckdb_ruleutils.h | 1 + src/pgduckdb_ruleutils.cpp | 27 ++++++++++ src/vendor/pg_ruleutils_14.c | 14 +---- src/vendor/pg_ruleutils_15.c | 14 +---- src/vendor/pg_ruleutils_16.c | 14 +---- src/vendor/pg_ruleutils_17.c | 14 +---- test/regression/expected/temporary_tables.out | 53 ++++++++++++++++++- test/regression/sql/temporary_tables.sql | 26 ++++++++- 8 files changed, 113 insertions(+), 50 deletions(-) diff --git a/include/pgduckdb/pgduckdb_ruleutils.h b/include/pgduckdb/pgduckdb_ruleutils.h index c6d05aa2..a090f63e 100644 --- a/include/pgduckdb/pgduckdb_ruleutils.h +++ b/include/pgduckdb/pgduckdb_ruleutils.h @@ -4,5 +4,6 @@ char *pgduckdb_relation_name(Oid relid); char *pgduckdb_function_name(Oid function_oid); char *pgduckdb_get_querydef(Query *); char *pgduckdb_get_tabledef(Oid relation_id); +bool pgduckdb_contains_insert_target_entry(Node *node, void *context); List *pgduckdb_db_and_schema(const char *postgres_schema_name, bool is_duckdb_table); const char *pgduckdb_db_and_schema_string(const char *postgres_schema_name, bool is_duckdb_table); diff --git a/src/pgduckdb_ruleutils.cpp b/src/pgduckdb_ruleutils.cpp index cbe9ec4f..c4881ed7 100644 --- a/src/pgduckdb_ruleutils.cpp +++ b/src/pgduckdb_ruleutils.cpp @@ -8,6 +8,7 @@ extern "C" { #include "catalog/pg_class.h" #include "catalog/pg_collation.h" #include "commands/dbcommands.h" +#include "nodes/nodeFuncs.h" #include "lib/stringinfo.h" #include "utils/builtins.h" #include "utils/guc.h" @@ -366,4 +367,30 @@ pgduckdb_get_tabledef(Oid relation_oid) { return (buffer.data); } + +/* + * Recursively check Const nodes and Var nodes for handling more complex Const nodes + */ +bool +pgduckdb_contains_insert_target_entry(Node *node, void *context) { + if (node == NULL) { + return false; + } + + if (IsA(node, Var)) { + return false; + } else if (IsA(node, Const)) { + /* If location is -1, it comes from the DEFAULT clause */ + Const *con = (Const *) node; + if (con->location == -1) { + return true; + } + } + +#if PG_VERSION_NUM >= 160000 + return expression_tree_walker(node, pgduckdb_contains_insert_target_entry, context); +#else + return expression_tree_walker(node, (bool (*)())((void *)pgduckdb_contains_insert_target_entry), context); +#endif +} } diff --git a/src/vendor/pg_ruleutils_14.c b/src/vendor/pg_ruleutils_14.c index c00eeb2f..1333e747 100644 --- a/src/vendor/pg_ruleutils_14.c +++ b/src/vendor/pg_ruleutils_14.c @@ -6641,19 +6641,9 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if (values_rte) + if (values_rte || select_rte) { - if (!(IsA(tle->expr, Var))) - continue; - } - else if (select_rte) - { - /* - * If it's INSERT... SELECT needs to make more careful decisions about - * Const structures. If location is -1, it comes from the DEFAULT clause - */ - if (IsA(tle->expr, Const) && - ((Const *) tle->expr)->location == -1) + if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) continue; } diff --git a/src/vendor/pg_ruleutils_15.c b/src/vendor/pg_ruleutils_15.c index 897c94d0..1d901c89 100644 --- a/src/vendor/pg_ruleutils_15.c +++ b/src/vendor/pg_ruleutils_15.c @@ -6722,19 +6722,9 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if (values_rte) + if (values_rte || select_rte) { - if (!(IsA(tle->expr, Var))) - continue; - } - else if (select_rte) - { - /* - * If it's INSERT... SELECT needs to make more careful decisions about - * Const structures. If location is -1, it comes from the DEFAULT clause - */ - if (IsA(tle->expr, Const) && - ((Const *) tle->expr)->location == -1) + if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) continue; } diff --git a/src/vendor/pg_ruleutils_16.c b/src/vendor/pg_ruleutils_16.c index a7dc97f9..9ea5a4a0 100644 --- a/src/vendor/pg_ruleutils_16.c +++ b/src/vendor/pg_ruleutils_16.c @@ -6682,19 +6682,9 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if (values_rte) + if (values_rte || select_rte) { - if (!(IsA(tle->expr, Var))) - continue; - } - else if (select_rte) - { - /* - * If it's INSERT... SELECT needs to make more careful decisions about - * Const structures. If location is -1, it comes from the DEFAULT clause - */ - if (IsA(tle->expr, Const) && - ((Const *) tle->expr)->location == -1) + if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) continue; } diff --git a/src/vendor/pg_ruleutils_17.c b/src/vendor/pg_ruleutils_17.c index 480a9ba2..784c96b6 100644 --- a/src/vendor/pg_ruleutils_17.c +++ b/src/vendor/pg_ruleutils_17.c @@ -6696,19 +6696,9 @@ get_insert_query_def(Query *query, deparse_context *context, * If it's an INSERT ... SELECT or multi-row VALUES, the entry * with the default value is ignored unless it is specified */ - if (values_rte) + if (values_rte || select_rte) { - if (!(IsA(tle->expr, Var))) - continue; - } - else if (select_rte) - { - /* - * If it's INSERT... SELECT needs to make more careful decisions about - * Const structures. If location is -1, it comes from the DEFAULT clause - */ - if (IsA(tle->expr, Const) && - ((Const *) tle->expr)->location == -1) + if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) continue; } diff --git a/test/regression/expected/temporary_tables.out b/test/regression/expected/temporary_tables.out index e97adf91..7dea15d0 100644 --- a/test/regression/expected/temporary_tables.out +++ b/test/regression/expected/temporary_tables.out @@ -329,4 +329,55 @@ SELECT * FROM tb; 3 | 3 | tatb (8 rows) -DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; +CREATE TEMP TABLE tc (a int DEFAULT 3, b int, c varchar DEFAULT 'pg_duckdb', d varchar DEFAULT 'a' || 'b', e int DEFAULT 1 + 2) USING duckdb; +INSERT INTO tc (a) VALUES (123), (456); +INSERT INTO tc (b) VALUES (123), (456); +INSERT INTO tc (c) VALUES ('ta'), ('tb'); +SELECT * FROM tc; + a | b | c | d | e +-----+-----+-----------+----+--- + 123 | | pg_duckdb | ab | 3 + 456 | | pg_duckdb | ab | 3 + 3 | 123 | pg_duckdb | ab | 3 + 3 | 456 | pg_duckdb | ab | 3 + 3 | | ta | ab | 3 + 3 | | tb | ab | 3 +(6 rows) + +TRUNCATE TABLE tc; +INSERT INTO tc (a) SELECT 789; +INSERT INTO tc (b) SELECT 789; +INSERT INTO tc (a) SELECT * FROM t_heap; +INSERT INTO tc (b) SELECT * FROM t_heap; +SELECT * FROM tc; + a | b | c | d | e +-----+-----+-----------+----+--- + 789 | | pg_duckdb | ab | 3 + 3 | 789 | pg_duckdb | ab | 3 + 1 | | pg_duckdb | ab | 3 + 3 | 1 | pg_duckdb | ab | 3 +(4 rows) + +TRUNCATE TABLE tc; +INSERT INTO tc (c) SELECT 'ta'; +INSERT INTO tc (c) SELECT 'ta' || 'tb'; +INSERT INTO tc (a) SELECT (2)::numeric; +INSERT INTO tc (b) SELECT (3)::numeric; +INSERT INTO tc (c) SELECT t.a FROM (SELECT 'ta' || 'tb' AS a) t; +INSERT INTO tc (b, c) SELECT t.b, t.c FROM (SELECT (3)::numeric AS b, 'ta' || 'tb' AS c) t; +INSERT INTO tc (a, b, c) SELECT 1, 2, 'tb'; +INSERT INTO tc SELECT * FROM (SELECT (3)::numeric AS a, (3)::numeric AS b, 'ta' || 'tb' AS c) t; +SELECT * FROM tc; + a | b | c | d | e +---+---+-----------+----+--- + 3 | | ta | ab | 3 + 3 | | tatb | ab | 3 + 2 | | pg_duckdb | ab | 3 + 3 | 3 | pg_duckdb | ab | 3 + 3 | | tatb | ab | 3 + 3 | 3 | tatb | ab | 3 + 1 | 2 | tb | ab | 3 + 3 | 3 | tatb | ab | 3 +(8 rows) + +DROP TABLE webpages, t, t_heap, t_heap2, ta, tb, tc; diff --git a/test/regression/sql/temporary_tables.sql b/test/regression/sql/temporary_tables.sql index 074bb0cc..73bbf564 100644 --- a/test/regression/sql/temporary_tables.sql +++ b/test/regression/sql/temporary_tables.sql @@ -203,4 +203,28 @@ INSERT INTO tb (a, b, c) SELECT 1, 2, 'tb'; INSERT INTO tb SELECT * FROM (SELECT (3)::numeric AS a, (3)::numeric AS b, 'ta' || 'tb' AS c) t; SELECT * FROM tb; -DROP TABLE webpages, t, t_heap, t_heap2, ta, tb; +CREATE TEMP TABLE tc (a int DEFAULT 3, b int, c varchar DEFAULT 'pg_duckdb', d varchar DEFAULT 'a' || 'b', e int DEFAULT 1 + 2) USING duckdb; +INSERT INTO tc (a) VALUES (123), (456); +INSERT INTO tc (b) VALUES (123), (456); +INSERT INTO tc (c) VALUES ('ta'), ('tb'); +SELECT * FROM tc; + +TRUNCATE TABLE tc; +INSERT INTO tc (a) SELECT 789; +INSERT INTO tc (b) SELECT 789; +INSERT INTO tc (a) SELECT * FROM t_heap; +INSERT INTO tc (b) SELECT * FROM t_heap; +SELECT * FROM tc; + +TRUNCATE TABLE tc; +INSERT INTO tc (c) SELECT 'ta'; +INSERT INTO tc (c) SELECT 'ta' || 'tb'; +INSERT INTO tc (a) SELECT (2)::numeric; +INSERT INTO tc (b) SELECT (3)::numeric; +INSERT INTO tc (c) SELECT t.a FROM (SELECT 'ta' || 'tb' AS a) t; +INSERT INTO tc (b, c) SELECT t.b, t.c FROM (SELECT (3)::numeric AS b, 'ta' || 'tb' AS c) t; +INSERT INTO tc (a, b, c) SELECT 1, 2, 'tb'; +INSERT INTO tc SELECT * FROM (SELECT (3)::numeric AS a, (3)::numeric AS b, 'ta' || 'tb' AS c) t; +SELECT * FROM tc; + +DROP TABLE webpages, t, t_heap, t_heap2, ta, tb, tc; From e2e3642a8b2691d2adde54d4c6ffa74f3a81a314 Mon Sep 17 00:00:00 2001 From: Leo-XM-Zeng Date: Tue, 3 Dec 2024 20:50:40 +0800 Subject: [PATCH 6/7] Comment changes --- src/pgduckdb_ruleutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pgduckdb_ruleutils.cpp b/src/pgduckdb_ruleutils.cpp index c4881ed7..49d7a192 100644 --- a/src/pgduckdb_ruleutils.cpp +++ b/src/pgduckdb_ruleutils.cpp @@ -369,7 +369,7 @@ pgduckdb_get_tabledef(Oid relation_oid) { } /* - * Recursively check Const nodes and Var nodes for handling more complex Const nodes + * Recursively check Const nodes and Var nodes for handling more complex DEFAULT clauses */ bool pgduckdb_contains_insert_target_entry(Node *node, void *context) { From 9a8f3a2b5d58d5b0436cb65515a0e3ad0b1a22e3 Mon Sep 17 00:00:00 2001 From: Leo-XM-Zeng Date: Wed, 4 Dec 2024 10:26:27 +0800 Subject: [PATCH 7/7] Add test cases and tweak code --- include/pgduckdb/pgduckdb_ruleutils.h | 2 +- src/pgduckdb_ruleutils.cpp | 10 +++++----- src/vendor/pg_ruleutils_14.c | 2 +- src/vendor/pg_ruleutils_15.c | 2 +- src/vendor/pg_ruleutils_16.c | 2 +- src/vendor/pg_ruleutils_17.c | 2 +- test/regression/expected/temporary_tables.out | 10 +++++++++- test/regression/sql/temporary_tables.sql | 6 +++++- 8 files changed, 24 insertions(+), 12 deletions(-) diff --git a/include/pgduckdb/pgduckdb_ruleutils.h b/include/pgduckdb/pgduckdb_ruleutils.h index a090f63e..d57e3015 100644 --- a/include/pgduckdb/pgduckdb_ruleutils.h +++ b/include/pgduckdb/pgduckdb_ruleutils.h @@ -4,6 +4,6 @@ char *pgduckdb_relation_name(Oid relid); char *pgduckdb_function_name(Oid function_oid); char *pgduckdb_get_querydef(Query *); char *pgduckdb_get_tabledef(Oid relation_id); -bool pgduckdb_contains_insert_target_entry(Node *node, void *context); +bool pgduckdb_is_not_default_expr(Node *node, void *context); List *pgduckdb_db_and_schema(const char *postgres_schema_name, bool is_duckdb_table); const char *pgduckdb_db_and_schema_string(const char *postgres_schema_name, bool is_duckdb_table); diff --git a/src/pgduckdb_ruleutils.cpp b/src/pgduckdb_ruleutils.cpp index 49d7a192..17b88161 100644 --- a/src/pgduckdb_ruleutils.cpp +++ b/src/pgduckdb_ruleutils.cpp @@ -372,25 +372,25 @@ pgduckdb_get_tabledef(Oid relation_oid) { * Recursively check Const nodes and Var nodes for handling more complex DEFAULT clauses */ bool -pgduckdb_contains_insert_target_entry(Node *node, void *context) { +pgduckdb_is_not_default_expr(Node *node, void *context) { if (node == NULL) { return false; } if (IsA(node, Var)) { - return false; + return true; } else if (IsA(node, Const)) { /* If location is -1, it comes from the DEFAULT clause */ Const *con = (Const *) node; - if (con->location == -1) { + if (con->location != -1) { return true; } } #if PG_VERSION_NUM >= 160000 - return expression_tree_walker(node, pgduckdb_contains_insert_target_entry, context); + return expression_tree_walker(node, pgduckdb_is_not_default_expr, context); #else - return expression_tree_walker(node, (bool (*)())((void *)pgduckdb_contains_insert_target_entry), context); + return expression_tree_walker(node, (bool (*)())((void *)pgduckdb_is_not_default_expr), context); #endif } } diff --git a/src/vendor/pg_ruleutils_14.c b/src/vendor/pg_ruleutils_14.c index 1333e747..572954ea 100644 --- a/src/vendor/pg_ruleutils_14.c +++ b/src/vendor/pg_ruleutils_14.c @@ -6643,7 +6643,7 @@ get_insert_query_def(Query *query, deparse_context *context, */ if (values_rte || select_rte) { - if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) + if (!pgduckdb_is_not_default_expr((Node *) tle, NULL)) continue; } diff --git a/src/vendor/pg_ruleutils_15.c b/src/vendor/pg_ruleutils_15.c index 1d901c89..42cabfc1 100644 --- a/src/vendor/pg_ruleutils_15.c +++ b/src/vendor/pg_ruleutils_15.c @@ -6724,7 +6724,7 @@ get_insert_query_def(Query *query, deparse_context *context, */ if (values_rte || select_rte) { - if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) + if (!pgduckdb_is_not_default_expr((Node *) tle, NULL)) continue; } diff --git a/src/vendor/pg_ruleutils_16.c b/src/vendor/pg_ruleutils_16.c index 9ea5a4a0..7ed7ae78 100644 --- a/src/vendor/pg_ruleutils_16.c +++ b/src/vendor/pg_ruleutils_16.c @@ -6684,7 +6684,7 @@ get_insert_query_def(Query *query, deparse_context *context, */ if (values_rte || select_rte) { - if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) + if (!pgduckdb_is_not_default_expr((Node *) tle, NULL)) continue; } diff --git a/src/vendor/pg_ruleutils_17.c b/src/vendor/pg_ruleutils_17.c index 784c96b6..b9b78a83 100644 --- a/src/vendor/pg_ruleutils_17.c +++ b/src/vendor/pg_ruleutils_17.c @@ -6698,7 +6698,7 @@ get_insert_query_def(Query *query, deparse_context *context, */ if (values_rte || select_rte) { - if (pgduckdb_contains_insert_target_entry((Node *) tle, NULL)) + if (!pgduckdb_is_not_default_expr((Node *) tle, NULL)) continue; } diff --git a/test/regression/expected/temporary_tables.out b/test/regression/expected/temporary_tables.out index 7dea15d0..cc426925 100644 --- a/test/regression/expected/temporary_tables.out +++ b/test/regression/expected/temporary_tables.out @@ -380,4 +380,12 @@ SELECT * FROM tc; 3 | 3 | tatb | ab | 3 (8 rows) -DROP TABLE webpages, t, t_heap, t_heap2, ta, tb, tc; +CREATE TEMP TABLE td (a int, ts timestamp default now()) USING duckdb; +INSERT INTO td (a) SELECT 1; +SELECT a FROM td; + a +--- + 1 +(1 row) + +DROP TABLE webpages, t, t_heap, t_heap2, ta, tb, tc, td; diff --git a/test/regression/sql/temporary_tables.sql b/test/regression/sql/temporary_tables.sql index 73bbf564..9515232c 100644 --- a/test/regression/sql/temporary_tables.sql +++ b/test/regression/sql/temporary_tables.sql @@ -227,4 +227,8 @@ INSERT INTO tc (a, b, c) SELECT 1, 2, 'tb'; INSERT INTO tc SELECT * FROM (SELECT (3)::numeric AS a, (3)::numeric AS b, 'ta' || 'tb' AS c) t; SELECT * FROM tc; -DROP TABLE webpages, t, t_heap, t_heap2, ta, tb, tc; +CREATE TEMP TABLE td (a int, ts timestamp default now()) USING duckdb; +INSERT INTO td (a) SELECT 1; +SELECT a FROM td; + +DROP TABLE webpages, t, t_heap, t_heap2, ta, tb, tc, td;