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,
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",
return rte;
}
-/*
- * 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
*/
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;
}
/* 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)
relation->schemaname, relation->relname)));
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",
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;