Commit 4a66f9dd authored by Tom Lane's avatar Tom Lane

Change scoping of table and join refnames to conform to SQL92: a JOIN

clause with an alias is a <subquery> and therefore hides table references
appearing within it, according to the spec.  This is the same as the
preliminary patch I posted to pgsql-patches yesterday, plus some really
grotty code in ruleutils.c to reverse-list a query tree with the correct
alias name depending on context.  I'd rather not have done that, but unless
we want to force another initdb for 7.1, there's no other way for now.
parent d42d31e7
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.159 2001/02/12 20:07:21 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.160 2001/02/14 21:34:59 tgl Exp $
*
*
* INTERFACE ROUTINES
......@@ -1533,7 +1533,6 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
bool updatePgAttribute)
{
Node *expr;
RangeTblEntry *rte;
char *adsrc;
Relation adrel;
Relation idescs[Num_pg_attrdef_indices];
......@@ -1551,16 +1550,12 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
expr = stringToNode(adbin);
/*
* deparse_expression needs a RangeTblEntry list, so make one
* deparse it
*/
rte = makeNode(RangeTblEntry);
rte->relname = RelationGetRelationName(rel);
rte->relid = RelationGetRelid(rel);
rte->eref = makeNode(Attr);
rte->eref->relname = RelationGetRelationName(rel);
rte->inh = false;
rte->inFromCl = true;
adsrc = deparse_expression(expr, makeList1(makeList1(rte)), false);
adsrc = deparse_expression(expr,
deparse_context_for(RelationGetRelationName(rel),
RelationGetRelid(rel)),
false);
values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
values[Anum_pg_attrdef_adnum - 1] = attnum;
......@@ -1619,7 +1614,6 @@ static void
StoreRelCheck(Relation rel, char *ccname, char *ccbin)
{
Node *expr;
RangeTblEntry *rte;
char *ccsrc;
Relation rcrel;
Relation idescs[Num_pg_relcheck_indices];
......@@ -1634,16 +1628,12 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
expr = (Node *) make_ands_explicit((List *) expr);
/*
* deparse_expression needs a RangeTblEntry list, so make one
* deparse it
*/
rte = makeNode(RangeTblEntry);
rte->relname = RelationGetRelationName(rel);
rte->relid = RelationGetRelid(rel);
rte->eref = makeNode(Attr);
rte->eref->relname = RelationGetRelationName(rel);
rte->inh = false;
rte->inFromCl = true;
ccsrc = deparse_expression(expr, makeList1(makeList1(rte)), false);
ccsrc = deparse_expression(expr,
deparse_context_for(RelationGetRelationName(rel),
RelationGetRelid(rel)),
false);
values[Anum_pg_relcheck_rcrelid - 1] = RelationGetRelid(rel);
values[Anum_pg_relcheck_rcname - 1] = DirectFunctionCall1(namein,
......@@ -1764,9 +1754,8 @@ AddRelationRawConstraints(Relation rel,
* sole rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
makeRangeTable(pstate, NULL);
rte = addRangeTableEntry(pstate, relname, NULL, false, true);
addRTEtoJoinList(pstate, rte);
addRTEtoQuery(pstate, rte, true, true);
/*
* Process column default expressions.
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.120 2001/01/29 00:39:20 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.121 2001/02/14 21:35:00 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
......@@ -1136,10 +1136,9 @@ AlterTableAddConstraint(char *relationName,
* the expression we can pass to ExecQual
*/
pstate = make_parsestate(NULL);
makeRangeTable(pstate, NULL);
rte = addRangeTableEntry(pstate, relationName, NULL,
false, true);
addRTEtoJoinList(pstate, rte);
addRTEtoQuery(pstate, rte, true, true);
/* Convert the A_EXPR in raw_expr into an EXPR */
expr = transformExpr(pstate, constr->raw_expr,
......
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.89 2001/01/24 19:43:01 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.90 2001/02/14 21:35:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -541,7 +541,8 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
{
if (indirection == NIL)
return basenode;
return (Node *) transformArraySubscripts(pstate, basenode,
return (Node *) transformArraySubscripts(pstate,
basenode, exprType(basenode),
indirection, false, NULL);
}
......@@ -558,13 +559,14 @@ static Node *
transformIdent(ParseState *pstate, Ident *ident, int precedence)
{
Node *result = NULL;
int sublevels_up;
/*
* try to find the ident as a relation ... but not if subscripts
* appear
*/
if (ident->indirection == NIL &&
refnameRangeTableEntry(pstate, ident->name) != NULL)
refnameRangeOrJoinEntry(pstate, ident->name, &sublevels_up) != NULL)
{
ident->isRel = TRUE;
result = (Node *) ident;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.98 2001/01/24 19:43:02 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.99 2001/02/14 21:35:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -427,6 +427,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
{
RangeTblEntry *rte;
int vnum;
Node *rteorjoin;
int sublevels_up;
/*
......@@ -434,9 +435,29 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
*/
refname = ((Ident *) arg)->name;
rte = refnameRangeTableEntry(pstate, refname);
if (rte == NULL)
rteorjoin = refnameRangeOrJoinEntry(pstate, refname,
&sublevels_up);
if (rteorjoin == NULL)
{
rte = addImplicitRTE(pstate, refname);
}
else if (IsA(rteorjoin, RangeTblEntry))
{
rte = (RangeTblEntry *) rteorjoin;
}
else if (IsA(rteorjoin, JoinExpr))
{
elog(ERROR,
"function applied to tuple is not supported for joins");
rte = NULL; /* keep compiler quiet */
}
else
{
elog(ERROR, "ParseFuncOrColumn: unexpected node type %d",
nodeTag(rteorjoin));
rte = NULL; /* keep compiler quiet */
}
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.51 2001/01/24 19:43:02 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.52 2001/02/14 21:35:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -229,6 +229,8 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
*
* pstate Parse state
* arrayBase Already-transformed expression for the array as a whole
* (may be NULL if we are handling an INSERT)
* arrayType OID of array's datatype
* indirection Untransformed list of subscripts (must not be NIL)
* forceSlice If true, treat subscript as array slice in all cases
* assignFrom NULL for array fetch, else transformed expression for source.
......@@ -236,13 +238,13 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
ArrayRef *
transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
Oid arrayType,
List *indirection,
bool forceSlice,
Node *assignFrom)
{
Oid typearray,
typeelement,
typeresult;
Oid elementType,
resultType;
HeapTuple type_tuple_array,
type_tuple_element;
Form_pg_type type_struct_array,
......@@ -254,28 +256,26 @@ transformArraySubscripts(ParseState *pstate,
ArrayRef *aref;
/* Get the type tuple for the array */
typearray = exprType(arrayBase);
type_tuple_array = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typearray),
ObjectIdGetDatum(arrayType),
0, 0, 0);
if (!HeapTupleIsValid(type_tuple_array))
elog(ERROR, "transformArraySubscripts: Cache lookup failed for array type %u",
typearray);
arrayType);
type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array);
typeelement = type_struct_array->typelem;
if (typeelement == InvalidOid)
elementType = type_struct_array->typelem;
if (elementType == InvalidOid)
elog(ERROR, "transformArraySubscripts: type %s is not an array",
NameStr(type_struct_array->typname));
/* Get the type tuple for the array element type */
type_tuple_element = SearchSysCache(TYPEOID,
ObjectIdGetDatum(typeelement),
ObjectIdGetDatum(elementType),
0, 0, 0);
if (!HeapTupleIsValid(type_tuple_element))
elog(ERROR, "transformArraySubscripts: Cache lookup failed for array element type %u",
typeelement);
elementType);
type_struct_element = (Form_pg_type) GETSTRUCT(type_tuple_element);
/*
......@@ -308,9 +308,9 @@ transformArraySubscripts(ParseState *pstate,
* array type if we are fetching a slice or storing.
*/
if (isSlice || assignFrom != NULL)
typeresult = typearray;
resultType = arrayType;
else
typeresult = typeelement;
resultType = elementType;
/*
* Transform the subscript expressions.
......@@ -359,7 +359,7 @@ transformArraySubscripts(ParseState *pstate,
if (assignFrom != NULL)
{
Oid typesource = exprType(assignFrom);
Oid typeneeded = isSlice ? typearray : typeelement;
Oid typeneeded = isSlice ? arrayType : elementType;
if (typesource != InvalidOid)
{
......@@ -385,7 +385,7 @@ transformArraySubscripts(ParseState *pstate,
aref = makeNode(ArrayRef);
aref->refattrlength = type_struct_array->typlen;
aref->refelemlength = type_struct_element->typlen;
aref->refelemtype = typeresult; /* XXX should save element type
aref->refelemtype = resultType; /* XXX should save element type
* too */
aref->refelembyval = type_struct_element->typbyval;
aref->refupperindexpr = upperIndexpr;
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.64 2001/01/24 19:43:02 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.65 2001/02/14 21:35:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -212,29 +212,37 @@ updateTargetListEntry(ParseState *pstate,
*/
if (indirection)
{
Attr *att = makeAttr(pstrdup(RelationGetRelationName(rd)),
colname);
Node *arrayBase;
ArrayRef *aref;
arrayBase = ParseNestedFuncOrColumn(pstate, att, EXPR_COLUMN_FIRST);
aref = transformArraySubscripts(pstate, arrayBase,
indirection,
pstate->p_is_insert,
tle->expr);
if (pstate->p_is_insert)
{
/*
* The command is INSERT INTO table (arraycol[subscripts]) ...
* so there is not really a source array value to work with.
* Let the executor do something reasonable, if it can. Notice
* that we forced transformArraySubscripts to treat the
* subscripting op as an array-slice op above, so the source
* data will have been coerced to array type.
* that we force transformArraySubscripts to treat the
* subscripting op as an array-slice op below, so the source
* data will have been coerced to the array type.
*/
arrayBase = NULL; /* signal there is no source array */
}
else
{
/*
* Build a Var for the array to be updated.
*/
aref->refexpr = NULL; /* signal there is no source array */
arrayBase = (Node *) make_var(pstate,
pstate->p_target_rangetblentry,
attrno);
}
aref = transformArraySubscripts(pstate,
arrayBase,
attrtype,
indirection,
pstate->p_is_insert,
tle->expr);
tle->expr = (Node *) aref;
}
else
......@@ -385,22 +393,19 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
/* ExpandAllTables()
* Turns '*' (in the target list) into a list of targetlist entries.
*
* tlist entries are generated for each relation appearing in the FROM list,
* which by now has been transformed into a joinlist.
* 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.)
*/
static List *
ExpandAllTables(ParseState *pstate)
{
List *target = NIL;
List *jt;
List *ns;
/* SELECT *; */
if (pstate->p_joinlist == NIL)
elog(ERROR, "Wildcard with no tables specified not allowed");
foreach(jt, pstate->p_joinlist)
foreach(ns, pstate->p_namespace)
{
Node *n = (Node *) lfirst(jt);
Node *n = (Node *) lfirst(ns);
if (IsA(n, RangeTblRef))
{
......@@ -431,6 +436,10 @@ ExpandAllTables(ParseState *pstate)
"\n\t%s", nodeToString(n));
}
/* Check for SELECT *; */
if (target == NIL)
elog(ERROR, "Wildcard with no tables specified not allowed");
return target;
}
......
This diff is collapsed.
......@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: primnodes.h,v 1.51 2001/01/24 19:43:26 momjian Exp $
* $Id: primnodes.h,v 1.52 2001/02/14 21:35:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -29,7 +29,7 @@ typedef struct FunctionCache *FunctionCachePtr;
* ----------------------------------------------------------------
*/
/*
/*--------------------
* Resdom (Result Domain)
*
* Notes:
......@@ -50,7 +50,7 @@ typedef struct FunctionCache *FunctionCachePtr;
*
* Both reskey and reskeyop are typically zero during parse/plan stages.
* The executor does not pay any attention to ressortgroupref.
*
*--------------------
*/
typedef struct Resdom
{
......@@ -129,7 +129,6 @@ typedef struct Expr
* list. But varnoold/varoattno continue to hold the original values.
* The code doesn't really need varnoold/varoattno, but they are very useful
* for debugging and interpreting completed plans, so we keep them around.
* ----------------
*/
#define INNER 65000
#define OUTER 65001
......@@ -153,7 +152,7 @@ typedef struct Var
AttrNumber varoattno; /* original value of varattno */
} Var;
/*
/*--------------------
* Oper
*
* NOTE: in the good old days 'opno' used to be both (or either, or
......@@ -169,7 +168,7 @@ typedef struct Var
* Note also that opid is not necessarily filled in immediately on creation
* of the node. The planner makes sure it is valid before passing the node
* tree to the executor, but during parsing/planning opid is typically 0.
*
*--------------------
*/
typedef struct Oper
{
......@@ -499,10 +498,14 @@ typedef struct RangeTblRef
* are not equivalent to ON() since they also affect the output column list.
*
* alias is an Attr node representing the AS alias-clause attached to the
* join expression, or NULL if no clause. During parse analysis, colnames
* is filled with a list of String nodes giving the column names (real or
* alias) of the output of the join, and colvars is filled with a list of
* expressions that can be copied to reference the output columns.
* join expression, or NULL if no clause. NB: presence or absence of the
* alias has a critical impact on semantics, because a join with an alias
* restricts visibility of the tables/columns inside it.
*
* During parse analysis, colnames is filled with a list of String nodes
* giving the column names (real or alias) of the output of the join,
* and colvars is filled with a list of expressions that can be copied to
* reference the output columns.
*----------
*/
typedef struct JoinExpr
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_clause.h,v 1.22 2001/01/24 19:43:27 momjian Exp $
* $Id: parse_clause.h,v 1.23 2001/02/14 21:35:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,10 +16,9 @@
#include "parser/parse_node.h"
extern void makeRangeTable(ParseState *pstate, List *frmList);
extern void lockTargetTable(ParseState *pstate, char *relname);
extern void setTargetTable(ParseState *pstate, char *relname,
bool inh, bool inJoinSet);
extern void transformFromClause(ParseState *pstate, List *frmList);
extern int setTargetTable(ParseState *pstate, char *relname,
bool inh, bool alsoSource);
extern bool interpretInhOption(InhOption inhOpt);
extern Node *transformWhereClause(ParseState *pstate, Node *where);
extern List *transformGroupClause(ParseState *pstate, List *grouplist,
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_node.h,v 1.24 2001/01/24 19:43:27 momjian Exp $
* $Id: parse_node.h,v 1.25 2001/02/14 21:35:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -18,6 +18,20 @@
/*
* State information used during parse analysis
*
* p_rtable: list of RTEs that will become the rangetable of the query.
* Note that neither relname nor refname of these entries are necessarily
* unique; searching the rtable by name is a bad idea.
*
* 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.
*/
typedef struct ParseState
{
......@@ -25,6 +39,7 @@ 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) */
int p_last_resno; /* last targetlist resno assigned */
List *p_forUpdate; /* FOR UPDATE clause, if any (see gram.y) */
bool p_hasAggs;
......@@ -42,6 +57,7 @@ extern Node *make_operand(char *opname, Node *tree,
extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
Oid arrayType,
List *indirection,
bool forceSlice,
Node *assignFrom);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_relation.h,v 1.21 2001/01/24 19:43:27 momjian Exp $
* $Id: parse_relation.h,v 1.22 2001/02/14 21:35:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -19,15 +19,11 @@
extern Node *refnameRangeOrJoinEntry(ParseState *pstate,
char *refname,
int *sublevels_up);
extern RangeTblEntry *refnameRangeTableEntry(ParseState *pstate,
char *refname);
extern int refnameRangeTablePosn(ParseState *pstate,
char *refname,
int *sublevels_up);
extern void checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
Node *namespace2);
extern int RTERangeTablePosn(ParseState *pstate,
RangeTblEntry *rte,
int *sublevels_up);
extern JoinExpr *scanJoinListForRefname(Node *jtnode, char *refname);
extern Node *colnameToVar(ParseState *pstate, char *colname);
extern Node *qualifiedNameToVar(ParseState *pstate, char *refname,
char *colname, bool implicitRTEOK);
......@@ -40,7 +36,8 @@ extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate,
Query *subquery,
Attr *alias,
bool inFromCl);
extern void addRTEtoJoinList(ParseState *pstate, RangeTblEntry *rte);
extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
bool addToJoinList, bool addToNameSpace);
extern RangeTblEntry *addImplicitRTE(ParseState *pstate, char *relname);
extern void expandRTE(ParseState *pstate, RangeTblEntry *rte,
List **colnames, List **colvars);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: builtins.h,v 1.146 2001/01/24 19:43:28 momjian Exp $
* $Id: builtins.h,v 1.147 2001/02/14 21:35:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -325,8 +325,9 @@ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
extern Datum pg_get_viewdef(PG_FUNCTION_ARGS);
extern Datum pg_get_indexdef(PG_FUNCTION_ARGS);
extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
extern char *deparse_expression(Node *expr, List *rangetables,
extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix);
extern List *deparse_context_for(char *relname, Oid relid);
/* selfuncs.c */
extern Datum eqsel(PG_FUNCTION_ARGS);
......
......@@ -67,7 +67,7 @@ Each table referenced in the query is represented by a <A
HREF="../../include/nodes/parsenodes.h"> RangeTableEntry,</A> and they
are linked together to form the <I>range table</I> of the query, which
is generated by <A HREF="../../backend/parser/parse_clause.c">
makeRangeTable().</A> Query.rtable holds the query's range table.<P>
transformFromClause().</A> Query.rtable holds the query's range table.<P>
Certain queries, like <I>SELECT,</I> return columns of data. Other
......
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