aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/Makefile5
-rw-r--r--src/backend/parser/analyze.c14
-rw-r--r--src/backend/parser/parse_clause.c59
-rw-r--r--src/backend/parser/parse_enr.c29
-rw-r--r--src/backend/parser/parse_node.c2
-rw-r--r--src/backend/parser/parse_relation.c143
-rw-r--r--src/backend/parser/parse_target.c2
7 files changed, 238 insertions, 16 deletions
diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index df9a9fbb35e..4b97f838036 100644
--- a/src/backend/parser/Makefile
+++ b/src/backend/parser/Makefile
@@ -14,8 +14,9 @@ override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS)
OBJS= analyze.o gram.o scan.o parser.o \
parse_agg.o parse_clause.o parse_coerce.o parse_collate.o parse_cte.o \
- parse_expr.o parse_func.o parse_node.o parse_oper.o parse_param.o \
- parse_relation.o parse_target.o parse_type.o parse_utilcmd.o scansup.o
+ parse_enr.o parse_expr.o parse_func.o parse_node.o parse_oper.o \
+ parse_param.o parse_relation.o parse_target.o parse_type.o \
+ parse_utilcmd.o scansup.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 8f11c46621e..811fccaec97 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -94,7 +94,8 @@ static bool test_raw_expression_coverage(Node *node, void *context);
*/
Query *
parse_analyze(RawStmt *parseTree, const char *sourceText,
- Oid *paramTypes, int numParams)
+ Oid *paramTypes, int numParams,
+ QueryEnvironment *queryEnv)
{
ParseState *pstate = make_parsestate(NULL);
Query *query;
@@ -106,6 +107,8 @@ parse_analyze(RawStmt *parseTree, const char *sourceText,
if (numParams > 0)
parse_fixed_parameters(pstate, paramTypes, numParams);
+ pstate->p_queryEnv = queryEnv;
+
query = transformTopLevelStmt(pstate, parseTree);
if (post_parse_analyze_hook)
@@ -2799,6 +2802,15 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
LCS_asString(lc->strength)),
parser_errposition(pstate, thisrel->location)));
break;
+ case RTE_NAMEDTUPLESTORE:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /*------
+ translator: %s is a SQL row locking clause such as FOR UPDATE */
+ errmsg("%s cannot be applied to a named tuplestore",
+ LCS_asString(lc->strength)),
+ parser_errposition(pstate, thisrel->location)));
+ break;
default:
elog(ERROR, "unrecognized RTE type: %d",
(int) rte->rtekind);
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 4f391d2d411..e268a127d13 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -59,9 +59,12 @@ static Node *transformJoinUsingClause(ParseState *pstate,
List *leftVars, List *rightVars);
static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
List *namespace);
+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,
@@ -181,6 +184,14 @@ 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)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("relation \"%s\" cannot be the target of a modifying statement",
+ relation->relname)));
+
/* Close old target; this could only happen for multi-action rules */
if (pstate->p_target_relation != NULL)
heap_close(pstate->p_target_relation, NoLock);
@@ -435,6 +446,20 @@ transformCTEReference(ParseState *pstate, RangeVar *r,
}
/*
+ * 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 *
@@ -1021,6 +1046,24 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
return tablesample;
}
+
+static RangeTblEntry *
+getRTEForSpecialRelationTypes(ParseState *pstate, RangeVar *rv)
+{
+
+ CommonTableExpr *cte;
+ Index levelsup;
+ RangeTblEntry *rte = 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);
+
+ return rte;
+}
+
/*
* transformFromClauseItem -
* Transform a FROM-clause item, adding any required entries to the
@@ -1055,18 +1098,14 @@ transformFromClauseItem(ParseState *pstate, Node *n,
RangeTblEntry *rte = NULL;
int rtindex;
- /* if it is an unqualified name, it might be a CTE reference */
+ /*
+ * if it is an unqualified name, it might be a CTE or tuplestore
+ * reference
+ */
if (!rv->schemaname)
- {
- CommonTableExpr *cte;
- Index levelsup;
-
- cte = scanNameSpaceForCTE(pstate, rv->relname, &levelsup);
- if (cte)
- rte = transformCTEReference(pstate, rv, cte, levelsup);
- }
+ rte = getRTEForSpecialRelationTypes(pstate, rv);
- /* if not found as a CTE, must be a table reference */
+ /* if not found above, must be a table reference */
if (!rte)
rte = transformTableEntry(pstate, rv);
diff --git a/src/backend/parser/parse_enr.c b/src/backend/parser/parse_enr.c
new file mode 100644
index 00000000000..1cfcf65a512
--- /dev/null
+++ b/src/backend/parser/parse_enr.c
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_enr.c
+ * parser support routines dealing with ephemeral named relations
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/parser/parse_enr.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "parser/parse_enr.h"
+
+bool
+name_matches_visible_ENR(ParseState *pstate, const char *refname)
+{
+ return (get_visible_ENR_metadata(pstate->p_queryEnv, refname) != NULL);
+}
+
+EphemeralNamedRelationMetadata
+get_visible_ENR(ParseState *pstate, const char *refname)
+{
+ return get_visible_ENR_metadata(pstate->p_queryEnv, refname);
+}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 30cc7dadca3..34006c70cd6 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -62,6 +62,8 @@ make_parsestate(ParseState *parentParseState)
pstate->p_paramref_hook = parentParseState->p_paramref_hook;
pstate->p_coerce_param_hook = parentParseState->p_coerce_param_hook;
pstate->p_ref_hook_state = parentParseState->p_ref_hook_state;
+ /* query environment stays in context for the whole parse analysis */
+ pstate->p_queryEnv = parentParseState->p_queryEnv;
}
return pstate;
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 2c19e0cbf58..7db13f37f72 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -25,6 +25,7 @@
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
+#include "parser/parse_enr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
@@ -282,6 +283,16 @@ isFutureCTE(ParseState *pstate, const char *refname)
}
/*
+ * Search the query's ephemeral named relation namespace for a relation
+ * matching the given unqualified refname.
+ */
+bool
+scanNameSpaceForENR(ParseState *pstate, const char *refname)
+{
+ return name_matches_visible_ENR(pstate, refname);
+}
+
+/*
* searchRangeTableForRel
* See if any RangeTblEntry could possibly match the RangeVar.
* If so, return a pointer to the RangeTblEntry; else return NULL.
@@ -302,6 +313,7 @@ searchRangeTableForRel(ParseState *pstate, RangeVar *relation)
const char *refname = relation->relname;
Oid relId = InvalidOid;
CommonTableExpr *cte = NULL;
+ bool isenr = false;
Index ctelevelsup = 0;
Index levelsup;
@@ -318,11 +330,16 @@ searchRangeTableForRel(ParseState *pstate, RangeVar *relation)
* unlocked.
*/
if (!relation->schemaname)
+ {
cte = scanNameSpaceForCTE(pstate, refname, &ctelevelsup);
- if (!cte)
+ if (!cte)
+ isenr = scanNameSpaceForENR(pstate, refname);
+ }
+
+ if (!cte && !isenr)
relId = RangeVarGetRelid(relation, NoLock, true);
- /* Now look for RTEs matching either the relation/CTE or the alias */
+ /* Now look for RTEs matching either the relation/CTE/ENR or the alias */
for (levelsup = 0;
pstate != NULL;
pstate = pstate->parentParseState, levelsup++)
@@ -342,6 +359,10 @@ searchRangeTableForRel(ParseState *pstate, RangeVar *relation)
rte->ctelevelsup + levelsup == ctelevelsup &&
strcmp(rte->ctename, refname) == 0)
return rte;
+ if (rte->rtekind == RTE_NAMEDTUPLESTORE &&
+ isenr &&
+ strcmp(rte->enrname, refname) == 0)
+ return rte;
if (strcmp(rte->eref->aliasname, refname) == 0)
return rte;
}
@@ -1139,12 +1160,17 @@ 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.
*/
- if (isFutureCTE(pstate, relation->relname))
+ else if (isFutureCTE(pstate, relation->relname))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist",
@@ -1940,6 +1966,102 @@ addRangeTableEntryForCTE(ParseState *pstate,
return rte;
}
+/*
+ * Add an entry for an ephemeral named relation reference to the pstate's
+ * range table (p_rtable).
+ *
+ * It is expected that the RangeVar, which up until now is only known to be an
+ * ephemeral named relation, will (in conjunction with the QueryEnvironment in
+ * the ParseState), create a RangeTblEntry for a specific *kind* of ephemeral
+ * named relation, based on enrtype.
+ *
+ * This is much like addRangeTableEntry() except that it makes an RTE for an
+ * ephemeral named relation.
+ */
+RangeTblEntry *
+addRangeTableEntryForENR(ParseState *pstate,
+ RangeVar *rv,
+ bool inFromCl)
+{
+ RangeTblEntry *rte = makeNode(RangeTblEntry);
+ Alias *alias = rv->alias;
+ char *refname = alias ? alias->aliasname : rv->relname;
+ EphemeralNamedRelationMetadata enrmd =
+ get_visible_ENR(pstate, rv->relname);
+ TupleDesc tupdesc;
+ int attno;
+
+ Assert(enrmd != NULL);
+
+ switch (enrmd->enrtype)
+ {
+ case ENR_NAMED_TUPLESTORE:
+ rte->rtekind = RTE_NAMEDTUPLESTORE;
+ break;
+
+ default:
+ elog(ERROR, "unexpected enrtype of %i", enrmd->enrtype);
+ return NULL; /* for fussy compilers */
+ }
+
+ /*
+ * Record dependency on a relation. This allows plans to be invalidated
+ * if they access transition tables linked to a table that is altered.
+ */
+ rte->relid = enrmd->reliddesc;
+
+ /*
+ * Build the list of effective column names using user-supplied aliases
+ * and/or actual column names. Also build the cannibalized fields.
+ */
+ tupdesc = ENRMetadataGetTupDesc(enrmd);
+ rte->eref = makeAlias(refname, NIL);
+ buildRelationAliases(tupdesc, alias, rte->eref);
+ rte->enrname = enrmd->name;
+ rte->enrtuples = enrmd->enrtuples;
+ rte->coltypes = NIL;
+ rte->coltypmods = NIL;
+ rte->colcollations = NIL;
+ for (attno = 1; attno <= tupdesc->natts; ++attno)
+ {
+ if (tupdesc->attrs[attno - 1]->atttypid == InvalidOid &&
+ !(tupdesc->attrs[attno - 1]->attisdropped))
+ elog(ERROR, "atttypid was invalid for column which has not been dropped from \"%s\"",
+ rv->relname);
+ rte->coltypes =
+ lappend_oid(rte->coltypes,
+ tupdesc->attrs[attno - 1]->atttypid);
+ rte->coltypmods =
+ lappend_int(rte->coltypmods,
+ tupdesc->attrs[attno - 1]->atttypmod);
+ rte->colcollations =
+ lappend_oid(rte->colcollations,
+ tupdesc->attrs[attno - 1]->attcollation);
+ }
+
+ /*
+ * Set flags and access permissions.
+ *
+ * ENRs are never checked for access rights.
+ */
+ rte->lateral = false;
+ rte->inh = false; /* never true for ENRs */
+ rte->inFromCl = inFromCl;
+
+ rte->requiredPerms = 0;
+ rte->checkAsUser = InvalidOid;
+ rte->selectedCols = NULL;
+
+ /*
+ * Add completed RTE to pstate's range table list, but not to join list
+ * nor namespace --- caller must do that if appropriate.
+ */
+ if (pstate != NULL)
+ pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
+ return rte;
+}
+
/*
* Has the specified refname been selected FOR UPDATE/FOR SHARE?
@@ -2292,6 +2414,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
case RTE_TABLEFUNC:
case RTE_VALUES:
case RTE_CTE:
+ case RTE_NAMEDTUPLESTORE:
{
/* Tablefunc, Values or CTE RTE */
ListCell *aliasp_item = list_head(rte->eref->colnames);
@@ -2705,6 +2828,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
case RTE_TABLEFUNC:
case RTE_VALUES:
case RTE_CTE:
+ case RTE_NAMEDTUPLESTORE:
{
/*
* tablefunc, VALUES or CTE RTE --- get type info from lists
@@ -2762,6 +2886,19 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
*/
result = false;
break;
+ case RTE_NAMEDTUPLESTORE:
+ {
+ Assert(rte->enrname);
+
+ /*
+ * We checked when we loaded ctecoltypes for the tuplestore
+ * that InvalidOid was only used for dropped columns, so it is
+ * safe to count on that here.
+ */
+ result =
+ (list_nth(rte->coltypes, attnum - 1) != InvalidOid);
+ }
+ break;
case RTE_JOIN:
{
/*
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 3b84140a9be..c46c3b38a49 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -397,6 +397,7 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
case RTE_FUNCTION:
case RTE_VALUES:
case RTE_TABLEFUNC:
+ case RTE_NAMEDTUPLESTORE:
/* not a simple relation, leave it unmarked */
break;
case RTE_CTE:
@@ -1505,6 +1506,7 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
{
case RTE_RELATION:
case RTE_VALUES:
+ case RTE_NAMEDTUPLESTORE:
/*
* This case should not occur: a column of a table or values list