Commit a4996a89 authored by Tom Lane's avatar Tom Lane

Replace the parser's namespace tree (which formerly had the same

representation as the jointree) with two lists of RTEs, one showing
the RTEs accessible by qualified names, and the other showing the RTEs
accessible by unqualified names.  I think this is conceptually simpler
than what we did before, and it's sure a whole lot easier to search.
This seems to eliminate the parse-time bottleneck for deeply nested
JOIN structures that was exhibited by phil@vodafone.
parent efe0d080
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.284 2005/04/14 20:03:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.285 2005/06/05 00:38:07 tgl Exp $
*
*
* INTERFACE ROUTINES
......@@ -1486,7 +1486,7 @@ AddRelationRawConstraints(Relation rel,
NULL,
false,
true);
addRTEtoQuery(pstate, rte, true, true);
addRTEtoQuery(pstate, rte, true, true, true);
/*
* Process column default expressions.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.159 2005/05/30 07:20:58 neilc Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.160 2005/06/05 00:38:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -4720,7 +4720,7 @@ ATPrepAlterColumnType(List **wqueue,
NULL,
false,
true);
addRTEtoQuery(pstate, rte, false, true);
addRTEtoQuery(pstate, rte, false, true, true);
transform = transformExpr(pstate, cmd->transform);
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.321 2005/04/28 21:47:14 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.322 2005/06/05 00:38:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -512,7 +512,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
Query *qry = makeNode(Query);
Query *selectQuery = NULL;
List *sub_rtable;
List *sub_namespace;
List *sub_relnamespace;
List *sub_varnamespace;
List *icolumns;
List *attrnos;
ListCell *icols;
......@@ -528,20 +529,23 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* SELECT. This can only happen if we are inside a CREATE RULE, and
* in that case we want the rule's OLD and NEW rtable entries to
* appear as part of the SELECT's rtable, not as outer references for
* it. (Kluge!) The SELECT's joinlist is not affected however. We
* it. (Kluge!) The SELECT's joinlist is not affected however. We
* must do this before adding the target table to the INSERT's rtable.
*/
if (stmt->selectStmt)
{
sub_rtable = pstate->p_rtable;
pstate->p_rtable = NIL;
sub_namespace = pstate->p_namespace;
pstate->p_namespace = NIL;
sub_relnamespace = pstate->p_relnamespace;
pstate->p_relnamespace = NIL;
sub_varnamespace = pstate->p_varnamespace;
pstate->p_varnamespace = NIL;
}
else
{
sub_rtable = NIL; /* not used, but keep compiler quiet */
sub_namespace = NIL;
sub_relnamespace = NIL;
sub_varnamespace = NIL;
}
/*
......@@ -578,7 +582,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* through 6.5 had bugs of just that nature...)
*/
sub_pstate->p_rtable = sub_rtable;
sub_pstate->p_namespace = sub_namespace;
sub_pstate->p_relnamespace = sub_relnamespace;
sub_pstate->p_varnamespace = sub_varnamespace;
/*
* Note: we are not expecting that extras_before and extras_after
......@@ -605,7 +610,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
rte = addRangeTableEntryForSubquery(pstate,
selectQuery,
makeAlias("*SELECT*", NIL),
true);
false);
rtr = makeNode(RangeTblRef);
/* assume new rte is at end */
rtr->rtindex = list_length(pstate->p_rtable);
......@@ -1481,8 +1486,8 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
*/
rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true);
/* no to join list, yes to namespace */
addRTEtoQuery(pstate, rte, false, true);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause,
"WHERE");
......@@ -1500,8 +1505,8 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
{
rte = addRangeTableEntry(pstate, stmt->relation, NULL,
false, true);
/* no to join list, yes to namespace */
addRTEtoQuery(pstate, rte, false, true);
/* no to join list, yes to namespaces */
addRTEtoQuery(pstate, rte, false, true, true);
}
ielem->expr = transformExpr(pstate, ielem->expr);
......@@ -1559,10 +1564,10 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
Assert(pstate->p_rtable == NIL);
oldrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("*OLD*", NIL),
false, true);
false, false);
newrte = addRangeTableEntryForRelation(pstate, rel,
makeAlias("*NEW*", NIL),
false, true);
false, false);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
......@@ -1572,24 +1577,22 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
* the one(s) that are relevant for the current kind of rule. In an
* UPDATE rule, quals must refer to OLD.field or NEW.field to be
* unambiguous, but there's no need to be so picky for INSERT &
* DELETE. (Note we marked the RTEs "inFromCl = true" above to allow
* unqualified references to their fields.) We do not add them to the
* joinlist.
* DELETE. We do not add them to the joinlist.
*/
switch (stmt->event)
{
case CMD_SELECT:
addRTEtoQuery(pstate, oldrte, false, true);
addRTEtoQuery(pstate, oldrte, false, true, true);
break;
case CMD_UPDATE:
addRTEtoQuery(pstate, oldrte, false, true);
addRTEtoQuery(pstate, newrte, false, true);
addRTEtoQuery(pstate, oldrte, false, true, true);
addRTEtoQuery(pstate, newrte, false, true, true);
break;
case CMD_INSERT:
addRTEtoQuery(pstate, newrte, false, true);
addRTEtoQuery(pstate, newrte, false, true, true);
break;
case CMD_DELETE:
addRTEtoQuery(pstate, oldrte, false, true);
addRTEtoQuery(pstate, oldrte, false, true, true);
break;
default:
elog(ERROR, "unrecognized event type: %d",
......@@ -1651,10 +1654,9 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
/*
* Set up OLD/NEW in the rtable for this statement. The
* entries are marked not inFromCl because we don't want them
* to be referred to by unqualified field names nor "*" in the
* rule actions. We must add them to the namespace, however,
* or they won't be accessible at all. We decide later
* entries are added only to relnamespace, not varnamespace,
* because we don't want them to be referred to by unqualified
* field names nor "*" in the rule actions. We decide later
* whether to put them in the joinlist.
*/
oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
......@@ -1665,8 +1667,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
false, false);
oldrte->requiredPerms = 0;
newrte->requiredPerms = 0;
addRTEtoQuery(sub_pstate, oldrte, false, true);
addRTEtoQuery(sub_pstate, newrte, false, true);
addRTEtoQuery(sub_pstate, oldrte, false, true, false);
addRTEtoQuery(sub_pstate, newrte, false, true, false);
/* Transform the rule action statement */
top_subqry = transformStmt(sub_pstate, action,
......@@ -1776,7 +1778,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
/* hack so we can use addRTEtoQuery() */
sub_pstate->p_rtable = sub_qry->rtable;
sub_pstate->p_joinlist = sub_qry->jointree->fromlist;
addRTEtoQuery(sub_pstate, oldrte, true, false);
addRTEtoQuery(sub_pstate, oldrte, true, false, false);
sub_qry->jointree->fromlist = sub_pstate->p_joinlist;
}
......@@ -1906,10 +1908,10 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
*dtlist;
List *targetvars,
*targetnames,
*sv_namespace,
*sv_relnamespace,
*sv_varnamespace,
*sv_rtable;
RangeTblEntry *jrte;
RangeTblRef *jrtr;
int tllen;
qry->commandType = CMD_SELECT;
......@@ -2027,7 +2029,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
/*
* As a first step towards supporting sort clauses that are
* expressions using the output columns, generate a namespace entry
* expressions using the output columns, generate a varnamespace entry
* that makes the output columns visible. A Join RTE node is handy
* for this, since we can easily control the Vars generated upon
* matches.
......@@ -2041,15 +2043,16 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
JOIN_INNER,
targetvars,
NULL,
true);
jrtr = makeNode(RangeTblRef);
jrtr->rtindex = 1; /* only entry in dummy rtable */
false);
sv_rtable = pstate->p_rtable;
pstate->p_rtable = list_make1(jrte);
sv_namespace = pstate->p_namespace;
pstate->p_namespace = list_make1(jrtr);
sv_relnamespace = pstate->p_relnamespace;
pstate->p_relnamespace = NIL; /* no qualified names allowed */
sv_varnamespace = pstate->p_varnamespace;
pstate->p_varnamespace = list_make1(jrte);
/*
* For now, we don't support resjunk sort clauses on the output of a
......@@ -2064,8 +2067,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
&qry->targetList,
false /* no unknowns expected */ );
pstate->p_namespace = sv_namespace;
pstate->p_rtable = sv_rtable;
pstate->p_relnamespace = sv_relnamespace;
pstate->p_varnamespace = sv_varnamespace;
if (tllen != list_length(qry->targetList))
ereport(ERROR,
......@@ -2164,7 +2168,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
* happen because the namespace will be empty, but it could happen
* if we are inside a rule.
*/
if (pstate->p_namespace)
if (pstate->p_relnamespace || pstate->p_varnamespace)
{
if (contain_vars_of_level((Node *) selectQuery, 1))
ereport(ERROR,
......
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.135 2005/06/04 19:19:42 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.136 2005/06/05 00:38:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -750,52 +750,32 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
* ExpandAllTables()
* Turns '*' (in the target list) into a list of targetlist entries.
*
* tlist entries are generated for each relation appearing at the top level
* of the query's namespace, except for RTEs marked not inFromCl. (These
* may include NEW/OLD pseudo-entries, implicit RTEs, etc.)
* tlist entries are generated for each relation appearing in the query's
* varnamespace. We do not consider relnamespace because that would include
* input tables of aliasless JOINs, NEW/OLD pseudo-entries, implicit RTEs,
* etc.
*/
static List *
ExpandAllTables(ParseState *pstate)
{
List *target = NIL;
bool found_table = false;
ListCell *ns;
foreach(ns, pstate->p_namespace)
{
Node *n = (Node *) lfirst(ns);
int rtindex;
RangeTblEntry *rte;
ListCell *l;
if (IsA(n, RangeTblRef))
rtindex = ((RangeTblRef *) n)->rtindex;
else if (IsA(n, JoinExpr))
rtindex = ((JoinExpr *) n)->rtindex;
else
{
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n));
rtindex = 0; /* keep compiler quiet */
}
/* Check for SELECT *; */
if (!pstate->p_varnamespace)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("SELECT * with no tables specified is not valid")));
/*
* Ignore added-on relations that were not listed in the FROM
* clause.
*/
rte = rt_fetch(rtindex, pstate->p_rtable);
if (!rte->inFromCl)
continue;
foreach(l, pstate->p_varnamespace)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
int rtindex = RTERangeTablePosn(pstate, rte, NULL);
found_table = true;
target = list_concat(target,
expandRelAttrs(pstate, rte, rtindex, 0));
}
/* Check for SELECT *; */
if (!found_table)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("SELECT * with no tables specified is not valid")));
return target;
}
......
......@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.199 2005/06/03 23:05:29 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.200 2005/06/05 00:38:10 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -4009,8 +4009,8 @@ get_from_clause(Query *query, const char *prefix, deparse_context *context)
* We use the query's jointree as a guide to what to print. However,
* we must ignore auto-added RTEs that are marked not inFromCl. (These
* can only appear at the top level of the jointree, so it's
* sufficient to check here.) Also ignore the rule pseudo-RTEs for NEW
* and OLD.
* sufficient to check here.) This check also ensures we ignore
* the rule pseudo-RTEs for NEW and OLD.
*/
foreach(l, query->jointree->fromlist)
{
......@@ -4023,10 +4023,6 @@ get_from_clause(Query *query, const char *prefix, deparse_context *context)
if (!rte->inFromCl)
continue;
if (strcmp(rte->eref->aliasname, "*NEW*") == 0)
continue;
if (strcmp(rte->eref->aliasname, "*OLD*") == 0)
continue;
}
if (first)
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.279 2005/06/03 23:05:29 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.280 2005/06/05 00:38:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -479,10 +479,10 @@ typedef struct DefElem
* FROM clause, but POSTQUEL allows you to refer to tables not listed,
* in which case a range table entry will be generated. We still support
* this POSTQUEL feature, although there is some doubt whether it's
* convenient or merely confusing. The flag is needed since an
* implicitly-added RTE shouldn't change the namespace for unqualified
* column names processed later, and it also shouldn't affect the
* expansion of '*'.
* convenient or merely confusing. The flag is not actually needed
* anymore during parsing, since the parser uses a separate "namespace"
* data structure to control visibility, but it is needed by ruleutils.c
* to determine whether RTEs should be included in decompiled queries.
*
* requiredPerms and checkAsUser specify run-time access permissions
* checks to be performed at query startup. The user must have *all*
......@@ -552,7 +552,7 @@ typedef struct RangeTblEntry
Alias *alias; /* user-written alias clause, if any */
Alias *eref; /* expanded reference names */
bool inh; /* inheritance requested? */
bool inFromCl; /* present in FROM clause */
bool inFromCl; /* present in FROM clause? */
AclMode requiredPerms; /* bitmask of required access permissions */
AclId checkAsUser; /* if not zero, check access as this user */
} RangeTblEntry;
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.43 2005/04/28 21:47:18 tgl Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.44 2005/06/05 00:38:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -27,12 +27,19 @@
* p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that
* will become the fromlist of the query's top-level FromExpr node.
*
* p_namespace: list of join items that represents the current namespace
* for table and column lookup. This may be just a subset of the rtable +
* joinlist, and/or may contain entries that are not yet added to the main
* joinlist. Note that an RTE that is present in p_namespace, but does not
* have its inFromCl flag set, is accessible only with an explicit qualifier;
* lookups of unqualified column names should ignore it.
* p_relnamespace: list of RTEs that represents the current namespace for
* table lookup, ie, those RTEs that are accessible by qualified names.
* This may be just a subset of the rtable + joinlist, and/or may contain
* entries that are not yet added to the main joinlist.
*
* p_varnamespace: list of RTEs that represents the current namespace for
* column lookup, ie, those RTEs that are accessible by unqualified names.
* This is different from p_relnamespace because a JOIN without an alias does
* not hide the contained tables (so they must still be in p_relnamespace)
* but it does hide their columns (unqualified references to the columns must
* refer to the JOIN, not the member tables). Also, we put POSTQUEL-style
* implicit RTEs into p_relnamespace but not p_varnamespace, so that they
* do not affect the set of columns available for unqualified references.
*
* p_paramtypes: an array of p_numparams type OIDs for $n parameter symbols
* (zeroth entry in array corresponds to $1). If p_variableparams is true, the
......@@ -49,7 +56,8 @@ typedef struct ParseState
List *p_rtable; /* range table so far */
List *p_joinlist; /* join items so far (will become FromExpr
* node's fromlist) */
List *p_namespace; /* current lookup namespace (join items) */
List *p_relnamespace; /* current namespace for relations */
List *p_varnamespace; /* current namespace for columns */
Oid *p_paramtypes; /* OIDs of types for $n parameter symbols */
int p_numparams; /* allocated size of p_paramtypes[] */
int p_next_resno; /* next targetlist resno to assign */
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.50 2005/06/04 19:19:42 tgl Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.51 2005/06/05 00:38:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -22,8 +22,8 @@ extern RangeTblEntry *refnameRangeTblEntry(ParseState *pstate,
const char *schemaname,
const char *refname,
int *sublevels_up);
extern void checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
Node *namespace2);
extern void checkNameSpaceConflicts(ParseState *pstate, List *namespace1,
List *namespace2);
extern int RTERangeTablePosn(ParseState *pstate,
RangeTblEntry *rte,
int *sublevels_up);
......@@ -64,7 +64,8 @@ extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate,
Alias *alias,
bool inFromCl);
extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
bool addToJoinList, bool addToNameSpace);
bool addToJoinList,
bool addToRelNameSpace, bool addToVarNameSpace);
extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation);
extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
bool include_dropped,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment