summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2017-05-08 08:18:41 +0000
committerPavan Deolasee2017-05-08 08:18:41 +0000
commit7b8dd5ed87768a589e8d62fdebff823fa2e73ff1 (patch)
tree702bd5a30d83176d42ca1c7023d3de86326a5674
parente81eae5b0deca6f0ced3d12dfafed32f8b863a43 (diff)
Use correct namespace while inserting rows via CTAS
We transform CREATE TABLE AS SELECT into a CREATE TABLE, followed by INSERT INTO. But the generated INSERT INTO statement was not qualifying the table name with schema, unless the original query has use qualified names. This results into incorrect behaviour when tables are created in implicit schemas such as "temporary" schemas. In passing also fix some places where we should be quoting identifiers correctly. Report, a test case and some initial analysis by Tomas Vondra. Patch and further test cases by me. Backpatched to XL9_5_STABLE
-rw-r--r--src/backend/rewrite/rewriteHandler.c8
-rw-r--r--src/backend/utils/adt/ruleutils.c15
-rw-r--r--src/test/regress/expected/xl_create_table.out76
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/xl_create_table.sql30
6 files changed, 120 insertions, 12 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 4815c35e58..4fd96d6a8c 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -4055,11 +4055,9 @@ QueryRewriteCTAS(Query *parsetree)
/* Now, finally build the INSERT INTO statement */
initStringInfo(&cquery);
- if (relation->schemaname)
- appendStringInfo(&cquery, "INSERT INTO %s.%s",
- relation->schemaname, relation->relname);
- else
- appendStringInfo(&cquery, "INSERT INTO %s", relation->relname);
+ appendStringInfo(&cquery, "INSERT INTO %s.%s",
+ quote_identifier(get_namespace_name(RangeVarGetCreationNamespace(relation))),
+ quote_identifier(relation->relname));
appendStringInfo(&cquery, " %s %s", selectstr,
into->skipData ? "LIMIT 0" : "");
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index c3834f097e..66e7553e51 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -6329,8 +6329,8 @@ get_utility_query_def(Query *query, deparse_context *context)
stmt->if_not_exists ? "IF NOT EXISTS " : "");
if (!istemp && relation->schemaname && relation->schemaname[0])
- appendStringInfo(buf, "%s.", relation->schemaname);
- appendStringInfo(buf, "%s", relation->relname);
+ appendStringInfo(buf, "%s.", quote_identifier(relation->schemaname));
+ appendStringInfo(buf, "%s", quote_identifier(relation->relname));
appendStringInfo(buf, "(");
foreach(column, stmt->tableElts)
@@ -6344,13 +6344,13 @@ get_utility_query_def(Query *query, deparse_context *context)
{
ColumnDef *coldef = (ColumnDef *) node;
TypeName *typename = coldef->typeName;
+ Type type;
#ifdef XCP
appendStringInfo(buf, "%s %s",
quote_identifier(coldef->colname),
format_type_with_typemod(typename->typeOid,
typename->typemod));
#else
- Type type;
/* error out if we have no recourse at all */
if (!OidIsValid(typename->typeOid))
@@ -6433,7 +6433,8 @@ get_utility_query_def(Query *query, deparse_context *context)
break;
case DISTTYPE_MODULO:
- appendStringInfo(buf, " DISTRIBUTE BY MODULO(%s)", stmt->distributeby->colname);
+ appendStringInfo(buf, " DISTRIBUTE BY MODULO(%s)",
+ quote_identifier(stmt->distributeby->colname));
break;
default:
@@ -6456,7 +6457,8 @@ get_utility_query_def(Query *query, deparse_context *context)
Assert(stmt->subcluster->members);
foreach(cell, stmt->subcluster->members)
{
- appendStringInfo(buf, " %s", strVal(lfirst(cell)));
+ appendStringInfo(buf, " %s",
+ quote_identifier(strVal(lfirst(cell))));
if (cell->next)
appendStringInfo(buf, ",");
}
@@ -6470,7 +6472,8 @@ get_utility_query_def(Query *query, deparse_context *context)
Assert(stmt->subcluster->members);
foreach(cell, stmt->subcluster->members)
{
- appendStringInfo(buf, " %s", strVal(lfirst(cell)));
+ appendStringInfo(buf, " %s",
+ quote_identifier(strVal(lfirst(cell))));
if (cell->next)
appendStringInfo(buf, ",");
}
diff --git a/src/test/regress/expected/xl_create_table.out b/src/test/regress/expected/xl_create_table.out
new file mode 100644
index 0000000000..c409129f0a
--- /dev/null
+++ b/src/test/regress/expected/xl_create_table.out
@@ -0,0 +1,76 @@
+-- check that CTAS inserts rows into correct table
+CREATE TABLE ctas_t1 AS SELECT 1;
+CREATE TEMP TABLE ctas_t1 AS SELECT 2;
+SELECT * FROM ctas_t1;
+ ?column?
+----------
+ 2
+(1 row)
+
+SELECT * FROM public.ctas_t1;
+ ?column?
+----------
+ 1
+(1 row)
+
+SELECT * FROM pg_temp.ctas_t1;
+ ?column?
+----------
+ 2
+(1 row)
+
+-- this drops the temp table
+DROP TABLE ctas_t1;
+-- also drop the public table
+DROP TABLE ctas_t1;
+-- same tests with special table name
+CREATE TABLE "ctas t1" AS SELECT 1;
+CREATE TEMP TABLE "ctas t1" AS SELECT 2;
+SELECT * FROM "ctas t1";
+ ?column?
+----------
+ 2
+(1 row)
+
+SELECT * FROM public."ctas t1";
+ ?column?
+----------
+ 1
+(1 row)
+
+SELECT * FROM pg_temp."ctas t1";
+ ?column?
+----------
+ 2
+(1 row)
+
+DROP TABLE "ctas t1";
+DROP TABLE "ctas t1";
+CREATE SCHEMA "ctas schema";
+SET search_path TO "ctas schema";
+CREATE TABLE "ctas t1" AS SELECT 1;
+CREATE TEMP TABLE "ctas t1" AS SELECT 2;
+SELECT * FROM "ctas t1";
+ ?column?
+----------
+ 2
+(1 row)
+
+SELECT * FROM public."ctas t1";
+ERROR: relation "public.ctas t1" does not exist
+LINE 1: SELECT * FROM public."ctas t1";
+ ^
+SELECT * FROM "ctas schema"."ctas t1";
+ ?column?
+----------
+ 1
+(1 row)
+
+SELECT * FROM pg_temp."ctas t1";
+ ?column?
+----------
+ 2
+(1 row)
+
+DROP TABLE "ctas t1";
+DROP TABLE "ctas t1";
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index ff7c8cac2e..d1a33b97a6 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -139,4 +139,4 @@ test: xc_prepared_xacts
test: xc_notrans_block
# This runs XL specific tests
-test: xl_primary_key xl_foreign_key xl_distribution_column_types xl_alter_table xl_distribution_column_types_modulo xl_plan_pushdown xl_functions xl_limitations xl_user_defined_functions xl_join xl_distributed_xact
+test: xl_primary_key xl_foreign_key xl_distribution_column_types xl_alter_table xl_distribution_column_types_modulo xl_plan_pushdown xl_functions xl_limitations xl_user_defined_functions xl_join xl_distributed_xact xl_create_table
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index e4ced6c15f..c08abd1a3d 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -196,3 +196,4 @@ test: xl_limitations
test: xl_user_defined_functions
test: xl_join
test: xl_distributed_xact
+test: xl_create_table
diff --git a/src/test/regress/sql/xl_create_table.sql b/src/test/regress/sql/xl_create_table.sql
new file mode 100644
index 0000000000..a790b8d433
--- /dev/null
+++ b/src/test/regress/sql/xl_create_table.sql
@@ -0,0 +1,30 @@
+-- check that CTAS inserts rows into correct table
+CREATE TABLE ctas_t1 AS SELECT 1;
+CREATE TEMP TABLE ctas_t1 AS SELECT 2;
+SELECT * FROM ctas_t1;
+SELECT * FROM public.ctas_t1;
+SELECT * FROM pg_temp.ctas_t1;
+-- this drops the temp table
+DROP TABLE ctas_t1;
+-- also drop the public table
+DROP TABLE ctas_t1;
+
+-- same tests with special table name
+CREATE TABLE "ctas t1" AS SELECT 1;
+CREATE TEMP TABLE "ctas t1" AS SELECT 2;
+SELECT * FROM "ctas t1";
+SELECT * FROM public."ctas t1";
+SELECT * FROM pg_temp."ctas t1";
+DROP TABLE "ctas t1";
+DROP TABLE "ctas t1";
+
+CREATE SCHEMA "ctas schema";
+SET search_path TO "ctas schema";
+CREATE TABLE "ctas t1" AS SELECT 1;
+CREATE TEMP TABLE "ctas t1" AS SELECT 2;
+SELECT * FROM "ctas t1";
+SELECT * FROM public."ctas t1";
+SELECT * FROM "ctas schema"."ctas t1";
+SELECT * FROM pg_temp."ctas t1";
+DROP TABLE "ctas t1";
+DROP TABLE "ctas t1";