On Mon, Oct 9, 2017 at 10:43 PM, Thomas Munro
<thomas.mu...@enterprisedb.com> wrote:
>
> I suppose we could consider moving the schemaname check into
> getRTEForSpecialRelationType(), since otherwise both callers need to
> do that (and as you discovered, one forgot).

Thanks for the feedback.  That was my first idea, but I assumed there
could be future use for this function on qualified RangeVar if it
wasn't done this way.

I agree it'd be much safer, so v2 attached, check moved in
getRTEForSpecialRelationType().
diff --git a/src/backend/parser/parse_clause.c 
b/src/backend/parser/parse_clause.c
index 9ff80b8b40..255f485494 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -184,8 +184,10 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
        RangeTblEntry *rte;
        int                     rtindex;
 
-       /* So far special relations are immutable; so they cannot be targets. */
+       /* Check if it's a CTE or tuplestore reference */
        rte = getRTEForSpecialRelationTypes(pstate, relation);
+
+       /* So far special relations are immutable; so they cannot be targets. */
        if (rte != NULL)
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1072,6 +1074,12 @@ transformRangeTableSample(ParseState *pstate, 
RangeTableSample *rts)
 }
 
 
+/*
+ * getRTEForSpecialRelationTypes
+ *
+ * If given RangeVar if a CTE reference or an EphemeralNamedRelation, return
+ * the transformed RangeVar otherwise return NULL
+ */
 static RangeTblEntry *
 getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
 {
@@ -1079,6 +1087,13 @@ getRTEForSpecialRelationTypes(ParseState *pstate, 
RangeVar *rv)
        Index           levelsup;
        RangeTblEntry *rte = NULL;
 
+       /*
+        * if it is a qualified name, it can't be a CTE or tuplestore
+        * reference
+        */
+       if (rv->schemaname)
+               return NULL;
+
        cte = scanNameSpaceForCTE(pstate, rv->relname, &levelsup);
        if (cte)
                rte = transformCTEReference(pstate, rv, cte, levelsup);
@@ -1119,15 +1134,11 @@ transformFromClauseItem(ParseState *pstate, Node *n,
                /* Plain relation reference, or perhaps a CTE reference */
                RangeVar   *rv = (RangeVar *) n;
                RangeTblRef *rtr;
-               RangeTblEntry *rte = NULL;
+               RangeTblEntry *rte;
                int                     rtindex;
 
-               /*
-                * if it is an unqualified name, it might be a CTE or tuplestore
-                * reference
-                */
-               if (!rv->schemaname)
-                       rte = getRTEForSpecialRelationTypes(pstate, rv);
+               /* Check if it's a CTE or tuplestore reference */
+               rte = getRTEForSpecialRelationTypes(pstate, rv);
 
                /* if not found above, must be a table reference */
                if (!rte)
diff --git a/src/test/regress/expected/with.out 
b/src/test/regress/expected/with.out
index c32a490580..53ea9991b2 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -2275,3 +2275,7 @@ with ordinality as (select 1 as x) select * from 
ordinality;
 -- check sane response to attempt to modify CTE relation
 WITH d AS (SELECT 42) INSERT INTO d VALUES (1);
 ERROR:  relation "d" cannot be the target of a modifying statement
+-- check qualified relation name doesn't conflict with CTE name
+CREATE TABLE public.self (id integer);
+WITH self AS (SELECT 42) INSERT INTO public.self SELECT * from self;
+DROP TABLE public.self;
diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql
index 8ae5184d0f..17f32c3c87 100644
--- a/src/test/regress/sql/with.sql
+++ b/src/test/regress/sql/with.sql
@@ -1031,3 +1031,8 @@ with ordinality as (select 1 as x) select * from 
ordinality;
 
 -- check sane response to attempt to modify CTE relation
 WITH d AS (SELECT 42) INSERT INTO d VALUES (1);
+
+-- check qualified relation name doesn't conflict with CTE name
+CREATE TABLE public.self (id integer);
+WITH self AS (SELECT 42) INSERT INTO public.self SELECT * from self;
+DROP TABLE public.self;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to