aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/parser/parse_clause.c74
-rw-r--r--src/backend/parser/parse_relation.c8
-rw-r--r--src/test/regress/expected/plpgsql.out8
-rw-r--r--src/test/regress/expected/with.out18
-rw-r--r--src/test/regress/sql/plpgsql.sql4
-rw-r--r--src/test/regress/sql/with.sql10
6 files changed, 59 insertions, 63 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 9ff80b8b403..af99e65aa7d 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -62,9 +62,6 @@ static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
static RangeTblEntry *getRTEForSpecialRelationTypes(ParseState *pstate,
RangeVar *rv);
static RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);
-static RangeTblEntry *transformCTEReference(ParseState *pstate, RangeVar *r,
- CommonTableExpr *cte, Index levelsup);
-static RangeTblEntry *transformENRReference(ParseState *pstate, RangeVar *r);
static RangeTblEntry *transformRangeSubselect(ParseState *pstate,
RangeSubselect *r);
static RangeTblEntry *transformRangeFunction(ParseState *pstate,
@@ -184,9 +181,12 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
RangeTblEntry *rte;
int rtindex;
- /* So far special relations are immutable; so they cannot be targets. */
- rte = getRTEForSpecialRelationTypes(pstate, relation);
- if (rte != NULL)
+ /*
+ * ENRs hide tables of the same name, so we need to check for them first.
+ * In contrast, CTEs don't hide tables (for this purpose).
+ */
+ if (relation->schemaname == NULL &&
+ scanNameSpaceForENR(pstate, relation->relname))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("relation \"%s\" cannot be the target of a modifying statement",
@@ -431,35 +431,6 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
}
/*
- * transformCTEReference --- transform a RangeVar that references a common
- * table expression (ie, a sub-SELECT defined in a WITH clause)
- */
-static RangeTblEntry *
-transformCTEReference(ParseState *pstate, RangeVar *r,
- CommonTableExpr *cte, Index levelsup)
-{
- RangeTblEntry *rte;
-
- rte = addRangeTableEntryForCTE(pstate, cte, levelsup, r, true);
-
- return rte;
-}
-
-/*
- * transformENRReference --- transform a RangeVar that references an ephemeral
- * named relation
- */
-static RangeTblEntry *
-transformENRReference(ParseState *pstate, RangeVar *r)
-{
- RangeTblEntry *rte;
-
- rte = addRangeTableEntryForENR(pstate, r, true);
-
- return rte;
-}
-
-/*
* transformRangeSubselect --- transform a sub-SELECT appearing in FROM
*/
static RangeTblEntry *
@@ -1071,19 +1042,32 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
return tablesample;
}
-
+/*
+ * getRTEForSpecialRelationTypes
+ *
+ * If given RangeVar refers to a CTE or an EphemeralNamedRelation,
+ * build and return an appropriate RTE, otherwise return NULL
+ */
static RangeTblEntry *
getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
{
CommonTableExpr *cte;
Index levelsup;
- RangeTblEntry *rte = NULL;
+ RangeTblEntry *rte;
+
+ /*
+ * 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);
- if (!rte && scanNameSpaceForENR(pstate, rv->relname))
- rte = transformENRReference(pstate, rv);
+ rte = addRangeTableEntryForCTE(pstate, cte, levelsup, rv, true);
+ else if (scanNameSpaceForENR(pstate, rv->relname))
+ rte = addRangeTableEntryForENR(pstate, rv, true);
+ else
+ rte = NULL;
return rte;
}
@@ -1119,15 +1103,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/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 4c5c684b441..a9273affb23 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1160,18 +1160,12 @@ parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
else
{
/*
- * An unqualified name might be a named ephemeral relation.
- */
- if (get_visible_ENR_metadata(pstate->p_queryEnv, relation->relname))
- rel = NULL;
-
- /*
* An unqualified name might have been meant as a reference to
* some not-yet-in-scope CTE. The bare "does not exist" message
* has proven remarkably unhelpful for figuring out such problems,
* so we take pains to offer a specific hint.
*/
- else if (isFutureCTE(pstate, relation->relname))
+ if (isFutureCTE(pstate, relation->relname))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist",
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index 7d3e9225bb2..bb3532676bd 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -5879,19 +5879,19 @@ CREATE FUNCTION transition_table_level2_bad_usage_func()
LANGUAGE plpgsql
AS $$
BEGIN
- INSERT INTO d VALUES (1000000, 1000000, 'x');
+ INSERT INTO dx VALUES (1000000, 1000000, 'x');
RETURN NULL;
END;
$$;
CREATE TRIGGER transition_table_level2_bad_usage_trigger
AFTER DELETE ON transition_table_level2
- REFERENCING OLD TABLE AS d
+ REFERENCING OLD TABLE AS dx
FOR EACH STATEMENT EXECUTE PROCEDURE
transition_table_level2_bad_usage_func();
DELETE FROM transition_table_level2
WHERE level2_no BETWEEN 301 AND 305;
-ERROR: relation "d" cannot be the target of a modifying statement
-CONTEXT: SQL statement "INSERT INTO d VALUES (1000000, 1000000, 'x')"
+ERROR: relation "dx" cannot be the target of a modifying statement
+CONTEXT: SQL statement "INSERT INTO dx VALUES (1000000, 1000000, 'x')"
PL/pgSQL function transition_table_level2_bad_usage_func() line 3 at SQL statement
DROP TRIGGER transition_table_level2_bad_usage_trigger
ON transition_table_level2;
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index c32a4905806..b4e0a1e83d8 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -2273,5 +2273,19 @@ with ordinality as (select 1 as x) select * from ordinality;
(1 row)
-- 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
+WITH test AS (SELECT 42) INSERT INTO test VALUES (1);
+ERROR: relation "test" does not exist
+LINE 1: WITH test AS (SELECT 42) INSERT INTO test VALUES (1);
+ ^
+-- check response to attempt to modify table with same name as a CTE (perhaps
+-- surprisingly it works, because CTEs don't hide tables from data-modifying
+-- statements)
+create table test (i int);
+with test as (select 42) insert into test select * from test;
+select * from test;
+ i
+----
+ 42
+(1 row)
+
+drop table test;
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 6c9399696bf..6620ea61729 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -4678,14 +4678,14 @@ CREATE FUNCTION transition_table_level2_bad_usage_func()
LANGUAGE plpgsql
AS $$
BEGIN
- INSERT INTO d VALUES (1000000, 1000000, 'x');
+ INSERT INTO dx VALUES (1000000, 1000000, 'x');
RETURN NULL;
END;
$$;
CREATE TRIGGER transition_table_level2_bad_usage_trigger
AFTER DELETE ON transition_table_level2
- REFERENCING OLD TABLE AS d
+ REFERENCING OLD TABLE AS dx
FOR EACH STATEMENT EXECUTE PROCEDURE
transition_table_level2_bad_usage_func();
diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql
index 8ae5184d0f1..baf65488a8e 100644
--- a/src/test/regress/sql/with.sql
+++ b/src/test/regress/sql/with.sql
@@ -1030,4 +1030,12 @@ create table foo (with ordinality); -- fail, WITH is a reserved word
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);
+WITH test AS (SELECT 42) INSERT INTO test VALUES (1);
+
+-- check response to attempt to modify table with same name as a CTE (perhaps
+-- surprisingly it works, because CTEs don't hide tables from data-modifying
+-- statements)
+create table test (i int);
+with test as (select 42) insert into test select * from test;
+select * from test;
+drop table test;