aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/util/clauses.c22
-rw-r--r--src/backend/parser/parse_expr.c174
-rw-r--r--src/backend/parser/parse_func.c272
-rw-r--r--src/backend/parser/parse_relation.c24
-rw-r--r--src/backend/parser/parse_target.c21
-rw-r--r--src/include/parser/parse_relation.h7
6 files changed, 227 insertions, 293 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index b05f760ade2..6aea0811bb2 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.167 2004/03/24 22:40:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.168 2004/04/02 19:06:57 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2550,16 +2550,6 @@ expression_tree_walker(Node *node,
return true;
}
break;
- case T_RangeVar:
- /*
- * Give a useful complaint if someone uses a bare relation name
- * in an expression (see comments in transformColumnRef()).
- */
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("relation reference \"%s\" cannot be used in an expression",
- ((RangeVar *) node)->relname)));
- break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));
@@ -3031,16 +3021,6 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
- case T_RangeVar:
- /*
- * Give a useful complaint if someone uses a bare relation name
- * in an expression (see comments in transformColumnRef()).
- */
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("relation reference \"%s\" cannot be used in an expression",
- ((RangeVar *) node)->relname)));
- break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 83daae9b62b..acee2b300e4 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.167 2004/03/24 22:40:29 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.168 2004/04/02 19:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,6 +40,8 @@ bool Transform_null_equals = false;
static Node *typecast_expression(ParseState *pstate, Node *expr,
TypeName *typename);
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
+static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
+ char *relname);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
@@ -932,34 +934,29 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
{
int numnames = length(cref->fields);
Node *node;
- RangeVar *rv;
int levels_up;
/*----------
* The allowed syntaxes are:
*
* A First try to resolve as unqualified column name;
- * if no luck, try to resolve as unqual. table name (A.*).
- * A.B A is an unqual. table name; B is either a
+ * if no luck, try to resolve as unqualified table name (A.*).
+ * A.B A is an unqualified table name; B is either a
* column or function name (trying column name first).
* A.B.C schema A, table B, col or func name C.
* A.B.C.D catalog A, schema B, table C, col or func D.
- * A.* A is an unqual. table name; means whole-row value.
+ * A.* A is an unqualified table name; means whole-row value.
* A.B.* whole-row value of table B in schema A.
* A.B.C.* whole-row value of table C in schema B in catalog A.
*
* We do not need to cope with bare "*"; that will only be accepted by
* the grammar at the top level of a SELECT list, and transformTargetList
- * will take care of it before it ever gets here.
+ * will take care of it before it ever gets here. Also, "A.*" etc will
+ * be expanded by transformTargetList if they appear at SELECT top level,
+ * so here we are only going to see them as function or operator inputs.
*
* Currently, if a catalog name is given then it must equal the current
* database name; we check it here and then discard it.
- *
- * For whole-row references, the result is an untransformed RangeVar,
- * which will work as the argument to a function call, but not in any
- * other context at present. (We could instead coerce to a whole-row Var,
- * but that will fail for subselect and join RTEs, because there is no
- * pg_type entry for their rowtypes.)
*----------
*/
switch (numnames)
@@ -1001,16 +998,12 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
if (cref->indirection == NIL &&
refnameRangeTblEntry(pstate, NULL, name,
&levels_up) != NULL)
- {
- rv = makeNode(RangeVar);
- rv->relname = name;
- rv->inhOpt = INH_DEFAULT;
- node = (Node *) rv;
- }
+ node = transformWholeRowRef(pstate, NULL, name);
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" does not exist", name)));
+ errmsg("column \"%s\" does not exist",
+ name)));
}
break;
}
@@ -1022,10 +1015,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
/* Whole-row reference? */
if (strcmp(name2, "*") == 0)
{
- rv = makeNode(RangeVar);
- rv->relname = name1;
- rv->inhOpt = INH_DEFAULT;
- node = (Node *) rv;
+ node = transformWholeRowRef(pstate, NULL, name1);
break;
}
@@ -1038,12 +1028,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
* try it as a function call. Here, we will create an
* implicit RTE for tables not already entered.
*/
- rv = makeNode(RangeVar);
- rv->relname = name1;
- rv->inhOpt = INH_DEFAULT;
+ node = transformWholeRowRef(pstate, NULL, name1);
node = ParseFuncOrColumn(pstate,
makeList1(makeString(name2)),
- makeList1(rv),
+ makeList1(node),
false, false, true);
}
break;
@@ -1057,11 +1045,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
/* Whole-row reference? */
if (strcmp(name3, "*") == 0)
{
- rv = makeNode(RangeVar);
- rv->schemaname = name1;
- rv->relname = name2;
- rv->inhOpt = INH_DEFAULT;
- node = (Node *) rv;
+ node = transformWholeRowRef(pstate, name1, name2);
break;
}
@@ -1070,13 +1054,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
if (node == NULL)
{
/* Try it as a function call */
- rv = makeNode(RangeVar);
- rv->schemaname = name1;
- rv->relname = name2;
- rv->inhOpt = INH_DEFAULT;
+ node = transformWholeRowRef(pstate, name1, name2);
node = ParseFuncOrColumn(pstate,
makeList1(makeString(name3)),
- makeList1(rv),
+ makeList1(node),
false, false, true);
}
break;
@@ -1100,11 +1081,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
/* Whole-row reference? */
if (strcmp(name4, "*") == 0)
{
- rv = makeNode(RangeVar);
- rv->schemaname = name2;
- rv->relname = name3;
- rv->inhOpt = INH_DEFAULT;
- node = (Node *) rv;
+ node = transformWholeRowRef(pstate, name2, name3);
break;
}
@@ -1113,13 +1090,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
if (node == NULL)
{
/* Try it as a function call */
- rv = makeNode(RangeVar);
- rv->schemaname = name2;
- rv->relname = name3;
- rv->inhOpt = INH_DEFAULT;
+ node = transformWholeRowRef(pstate, name2, name3);
node = ParseFuncOrColumn(pstate,
makeList1(makeString(name4)),
- makeList1(rv),
+ makeList1(node),
false, false, true);
}
break;
@@ -1137,6 +1111,99 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
}
/*
+ * Construct a whole-row reference to represent the notation "relation.*".
+ *
+ * In simple cases, this will be a Var with varno set to the correct range
+ * table entry, and varattno == 0 to signal that it references the whole
+ * tuple. (Use of zero here is unclean, since it could easily be confused
+ * with error cases, but it's not worth changing now.) The vartype indicates
+ * a rowtype; either a named composite type, or RECORD.
+ *
+ * We also need the ability to build a row-constructor expression, but the
+ * infrastructure for that doesn't exist just yet.
+ */
+static Node *
+transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname)
+{
+ Node *result;
+ RangeTblEntry *rte;
+ int vnum;
+ int sublevels_up;
+ Oid toid;
+
+ /* Look up the referenced RTE, creating it if needed */
+
+ rte = refnameRangeTblEntry(pstate, schemaname, relname,
+ &sublevels_up);
+
+ if (rte == NULL)
+ rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname));
+
+ vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
+
+ /* Build the appropriate referencing node */
+
+ switch (rte->rtekind)
+ {
+ case RTE_RELATION:
+ /* relation: the rowtype is a named composite type */
+ toid = get_rel_type_id(rte->relid);
+ if (!OidIsValid(toid))
+ elog(ERROR, "could not find type OID for relation %u",
+ rte->relid);
+ result = (Node *) makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
+ break;
+ case RTE_FUNCTION:
+ toid = exprType(rte->funcexpr);
+ if (toid == RECORDOID || get_typtype(toid) == 'c')
+ {
+ /* func returns composite; same as relation case */
+ result = (Node *) makeVar(vnum,
+ InvalidAttrNumber,
+ toid,
+ -1,
+ sublevels_up);
+ }
+ else
+ {
+ /*
+ * func returns scalar; instead of making a whole-row Var,
+ * just reference the function's scalar output. (XXX this
+ * seems a tad inconsistent, especially if "f.*" was
+ * explicitly written ...)
+ */
+ result = (Node *) makeVar(vnum,
+ 1,
+ toid,
+ -1,
+ sublevels_up);
+ }
+ break;
+ default:
+ /*
+ * RTE is a join or subselect. For the moment we represent this
+ * as a whole-row Var of RECORD type, but this will not actually
+ * work; need a row-constructor expression instead.
+ *
+ * XXX after fixing, be sure that unknown_attribute still
+ * does the right thing.
+ */
+ result = (Node *) makeVar(vnum,
+ InvalidAttrNumber,
+ RECORDOID,
+ -1,
+ sublevels_up);
+ break;
+ }
+
+ return result;
+}
+
+/*
* exprType -
* returns the Oid of the type of the expression. (Used for typechecking.)
*/
@@ -1294,19 +1361,6 @@ exprType(Node *expr)
case T_SetToDefault:
type = ((SetToDefault *) expr)->typeId;
break;
- case T_RangeVar:
-
- /*
- * If someone uses a bare relation name in an expression, we
- * will likely first notice a problem here (see comments in
- * transformColumnRef()). Issue an appropriate error message.
- */
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("relation reference \"%s\" cannot be used in an expression",
- ((RangeVar *) expr)->relname)));
- type = InvalidOid; /* keep compiler quiet */
- break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
type = InvalidOid; /* keep compiler quiet */
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 1677493abbc..deab6c2ad34 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.166 2004/04/01 21:28:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.167 2004/04/02 19:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,14 +32,14 @@
#include "utils/syscache.h"
-static Node *ParseComplexProjection(char *funcname, Node *first_arg);
+static Node *ParseComplexProjection(ParseState *pstate, char *funcname,
+ Node *first_arg);
static Oid **argtype_inherit(int nargs, Oid *argtypes);
static int find_inheritors(Oid relid, Oid **supervec);
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid);
-static void unknown_attribute(const char *schemaname, const char *relname,
- const char *attname);
+static void unknown_attribute(ParseState *pstate, Node *relref, char *attname);
/*
@@ -48,7 +48,9 @@ static void unknown_attribute(const char *schemaname, const char *relname,
* For historical reasons, Postgres tries to treat the notations tab.col
* and col(tab) as equivalent: if a single-argument function call has an
* argument of complex type and the (unqualified) function name matches
- * any attribute of the type, we take it as a column projection.
+ * any attribute of the type, we take it as a column projection. Conversely
+ * a function of a single complex-type argument can be written like a
+ * column reference, allowing functions to act like computed columns.
*
* Hence, both cases come through here. The is_column parameter tells us
* which syntactic construct is actually being dealt with, but this is
@@ -57,9 +59,7 @@ static void unknown_attribute(const char *schemaname, const char *relname,
* a single argument (the putative table), unqualified function name
* equal to the column name, and no aggregate decoration.
*
- * In the function-call case, the argument expressions have been transformed
- * already. In the column case, we may get either a transformed expression
- * or a RangeVar node as argument.
+ * The argument expressions (in fargs) must have been transformed already.
*/
Node *
ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
@@ -96,44 +96,32 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
}
/*
- * check for column projection: if function has one argument, and that
+ * Check for column projection: if function has one argument, and that
* argument is of complex type, and function name is not qualified,
* then the "function call" could be a projection. We also check that
* there wasn't any aggregate decoration.
*/
if (nargs == 1 && !agg_star && !agg_distinct && length(funcname) == 1)
{
- char *cname = strVal(lfirst(funcname));
+ Oid argtype = exprType(first_arg);
- /* Is it a not-yet-transformed RangeVar node? */
- if (IsA(first_arg, RangeVar))
+ if (argtype == RECORDOID || ISCOMPLEX(argtype))
{
- /* First arg is a relation. This could be a projection. */
- retval = qualifiedNameToVar(pstate,
- ((RangeVar *) first_arg)->schemaname,
- ((RangeVar *) first_arg)->relname,
- cname,
- true);
+ retval = ParseComplexProjection(pstate,
+ strVal(lfirst(funcname)),
+ first_arg);
if (retval)
return retval;
- }
- else if (ISCOMPLEX(exprType(first_arg)))
- {
/*
- * Attempt to handle projection of a complex argument. If
- * ParseComplexProjection can't handle the projection, we have
- * to keep going.
+ * If ParseComplexProjection doesn't recognize it as a projection,
+ * just press on.
*/
- retval = ParseComplexProjection(cname, first_arg);
- if (retval)
- return retval;
}
}
/*
* Okay, it's not a column projection, so it must really be a
- * function. Extract arg type info and transform RangeVar arguments
- * into varnodes of the appropriate form.
+ * function. Extract arg type info in preparation for function lookup.
*/
MemSet(actual_arg_types, 0, FUNC_MAX_ARGS * sizeof(Oid));
@@ -141,96 +129,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
foreach(i, fargs)
{
Node *arg = lfirst(i);
- Oid toid;
-
- if (IsA(arg, RangeVar))
- {
- char *schemaname;
- char *relname;
- RangeTblEntry *rte;
- int vnum;
- int sublevels_up;
-
- /*
- * a relation: look it up in the range table, or add if needed
- */
- schemaname = ((RangeVar *) arg)->schemaname;
- relname = ((RangeVar *) arg)->relname;
- rte = refnameRangeTblEntry(pstate, schemaname, relname,
- &sublevels_up);
-
- if (rte == NULL)
- rte = addImplicitRTE(pstate, (RangeVar *) arg);
-
- vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
-
- /*
- * The parameter to be passed to the function is the whole
- * tuple from the relation. We build a special VarNode to
- * reflect this -- it has varno set to the correct range table
- * entry, but has varattno == 0 to signal that the whole tuple
- * is the argument.
- */
- switch (rte->rtekind)
- {
- case RTE_RELATION:
- toid = get_rel_type_id(rte->relid);
- if (!OidIsValid(toid))
- elog(ERROR, "could not find type OID for relation %u",
- rte->relid);
- /* replace RangeVar in the arg list */
- lfirst(i) = makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
- break;
- case RTE_FUNCTION:
- toid = exprType(rte->funcexpr);
- if (get_typtype(toid) == 'c')
- {
- /* func returns composite; same as relation case */
- lfirst(i) = makeVar(vnum,
- InvalidAttrNumber,
- toid,
- -1,
- sublevels_up);
- }
- else
- {
- /* func returns scalar; use attno 1 instead */
- lfirst(i) = makeVar(vnum,
- 1,
- toid,
- -1,
- sublevels_up);
- }
- break;
- default:
-
- /*
- * RTE is a join or subselect; must fail for lack of a
- * named tuple type
- *
- * XXX FIXME
- */
- if (is_column)
- unknown_attribute(schemaname, relname,
- strVal(lfirst(funcname)));
- else
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot pass result of subquery or join \"%s\" to a function",
- relname)));
- toid = InvalidOid; /* keep compiler quiet */
- break;
- }
- }
- else
- toid = exprType(arg);
-
- actual_arg_types[argn++] = toid;
+ actual_arg_types[argn++] = exprType(arg);
}
/*
@@ -281,25 +181,9 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
*/
if (is_column)
{
- char *colname = strVal(lfirst(funcname));
- Oid relTypeId;
-
Assert(nargs == 1);
- if (IsA(first_arg, RangeVar))
- unknown_attribute(((RangeVar *) first_arg)->schemaname,
- ((RangeVar *) first_arg)->relname,
- colname);
- relTypeId = exprType(first_arg);
- if (!ISCOMPLEX(relTypeId))
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("attribute notation .%s applied to type %s, which is not a complex type",
- colname, format_type_be(relTypeId))));
- else
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("attribute \"%s\" not found in data type %s",
- colname, format_type_be(relTypeId))));
+ Assert(length(funcname) == 1);
+ unknown_attribute(pstate, first_arg, strVal(lfirst(funcname)));
}
/*
@@ -1284,80 +1168,92 @@ setup_field_select(Node *input, char *attname, Oid relid)
* handles function calls with a single argument that is of complex type.
* If the function call is actually a column projection, return a suitably
* transformed expression tree. If not, return NULL.
- *
- * NB: argument is expected to be transformed already, ie, not a RangeVar.
*/
static Node *
-ParseComplexProjection(char *funcname, Node *first_arg)
+ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
{
- Oid argtype = exprType(first_arg);
+ Oid argtype;
Oid argrelid;
AttrNumber attnum;
- FieldSelect *fselect;
-
- argrelid = typeidTypeRelid(argtype);
- if (!argrelid)
- return NULL; /* probably should not happen */
- attnum = get_attnum(argrelid, funcname);
- if (attnum == InvalidAttrNumber)
- return NULL; /* funcname does not match any column */
/*
- * Check for special cases where we don't want to return a
- * FieldSelect.
+ * Special case for whole-row Vars so that we can resolve (foo.*).bar
+ * even when foo is a reference to a subselect, join, or RECORD function.
+ * A bonus is that we avoid generating an unnecessary FieldSelect; our
+ * result can omit the whole-row Var and just be a Var for the selected
+ * field.
*/
- switch (nodeTag(first_arg))
+ if (IsA(first_arg, Var) &&
+ ((Var *) first_arg)->varattno == InvalidAttrNumber)
{
- case T_Var:
- {
- Var *var = (Var *) first_arg;
+ RangeTblEntry *rte;
- /*
- * If the Var is a whole-row tuple, we can just replace it
- * with a simple Var reference.
- */
- if (var->varattno == InvalidAttrNumber)
- {
- Oid vartype;
- int32 vartypmod;
+ rte = GetRTEByRangeTablePosn(pstate,
+ ((Var *) first_arg)->varno,
+ ((Var *) first_arg)->varlevelsup);
+ /* Return a Var if funcname matches a column, else NULL */
+ return scanRTEForColumn(pstate, rte, funcname);
+ }
- get_atttypetypmod(argrelid, attnum,
- &vartype, &vartypmod);
+ /*
+ * Else do it the hard way. Note that if the arg is of RECORD type,
+ * we will never recognize a column name, and always assume the item
+ * must be a function.
+ */
+ argtype = exprType(first_arg);
+ argrelid = typeidTypeRelid(argtype);
+ if (!argrelid)
+ return NULL; /* can only happen if RECORD */
- return (Node *) makeVar(var->varno,
- attnum,
- vartype,
- vartypmod,
- var->varlevelsup);
- }
- break;
- }
- default:
- break;
- }
+ attnum = get_attnum(argrelid, funcname);
+ if (attnum == InvalidAttrNumber)
+ return NULL; /* funcname does not match any column */
- /* Else generate a FieldSelect expression */
- fselect = setup_field_select(first_arg, funcname, argrelid);
- return (Node *) fselect;
+ /* Success, so generate a FieldSelect expression */
+ return (Node *) setup_field_select(first_arg, funcname, argrelid);
}
/*
- * Simple helper routine for delivering "column does not exist" error message
+ * helper routine for delivering "column does not exist" error message
*/
static void
-unknown_attribute(const char *schemaname, const char *relname,
- const char *attname)
+unknown_attribute(ParseState *pstate, Node *relref, char *attname)
{
- if (schemaname)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column %s.%s.%s does not exist",
- schemaname, relname, attname)));
- else
+ RangeTblEntry *rte;
+
+ if (IsA(relref, Var))
+ {
+ /* Reference the RTE by alias not by actual table name */
+ rte = GetRTEByRangeTablePosn(pstate,
+ ((Var *) relref)->varno,
+ ((Var *) relref)->varlevelsup);
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column %s.%s does not exist",
- relname, attname)));
+ rte->eref->aliasname, attname)));
+ }
+ else
+ {
+ /* Have to do it by reference to the type of the expression */
+ Oid relTypeId = exprType(relref);
+
+ if (ISCOMPLEX(relTypeId))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" not found in data type %s",
+ attname, format_type_be(relTypeId))));
+ else if (relTypeId == RECORDOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("could not identify column \"%s\" in record data type",
+ attname)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("column notation .%s applied to type %s, "
+ "which is not a composite type",
+ attname, format_type_be(relTypeId))));
+ }
}
/*
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 3e314bea963..4df92ee310c 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.92 2004/01/14 23:01:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.93 2004/04/02 19:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,8 +41,6 @@ static Node *scanNameSpaceForRelid(ParseState *pstate, Node *nsnode,
Oid relid);
static void scanNameSpaceForConflict(ParseState *pstate, Node *nsnode,
RangeTblEntry *rte1, const char *aliasname1);
-static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
- char *colname);
static bool isForUpdate(ParseState *pstate, char *refname);
static bool get_rte_attribute_is_dropped(RangeTblEntry *rte,
AttrNumber attnum);
@@ -425,6 +423,24 @@ RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up)
}
/*
+ * Given an RT index and nesting depth, find the corresponding RTE.
+ * This is the inverse of RTERangeTablePosn.
+ */
+RangeTblEntry *
+GetRTEByRangeTablePosn(ParseState *pstate,
+ int varno,
+ int sublevels_up)
+{
+ while (sublevels_up-- > 0)
+ {
+ pstate = pstate->parentParseState;
+ Assert(pstate != NULL);
+ }
+ Assert(varno > 0 && varno <= length(pstate->p_rtable));
+ return rt_fetch(varno, pstate->p_rtable);
+}
+
+/*
* scanRTEForColumn
* Search the column names of a single RTE for the given name.
* If found, return an appropriate Var node, else return NULL.
@@ -439,7 +455,7 @@ RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up)
* expression can only appear in a FROM clause, and any table named in
* FROM will be marked as requiring read access from the beginning.
*/
-static Node *
+Node *
scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
{
Node *result = NULL;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 6bed23f9064..c9c44ac2389 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.115 2004/02/13 01:08:20 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.116 2004/04/02 19:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -60,14 +60,6 @@ transformTargetEntry(ParseState *pstate,
if (expr == NULL)
expr = transformExpr(pstate, node);
- if (IsA(expr, RangeVar))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("relation reference \"%s\" cannot be used as a select-list entry",
- ((RangeVar *) expr)->relname),
- errhint("Write \"%s\".* to denote all the columns of the relation.",
- ((RangeVar *) expr)->relname)));
-
type_id = exprType(expr);
type_mod = exprTypmod(expr);
@@ -243,21 +235,12 @@ markTargetListOrigins(ParseState *pstate, List *targetlist)
static void
markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var)
{
- Index levelsup;
RangeTblEntry *rte;
AttrNumber attnum;
if (var == NULL || !IsA(var, Var))
return;
- levelsup = var->varlevelsup;
- while (levelsup-- > 0)
- {
- pstate = pstate->parentParseState;
- Assert(pstate != NULL);
- }
- Assert(var->varno > 0 &&
- (int) var->varno <= length(pstate->p_rtable));
- rte = rt_fetch(var->varno, pstate->p_rtable);
+ rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup);
attnum = var->varattno;
switch (rte->rtekind)
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index ca209c93028..0fa75d0297d 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.42 2003/11/29 22:41:09 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.43 2004/04/02 19:07:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,6 +27,11 @@ extern void checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
extern int RTERangeTablePosn(ParseState *pstate,
RangeTblEntry *rte,
int *sublevels_up);
+extern RangeTblEntry *GetRTEByRangeTablePosn(ParseState *pstate,
+ int varno,
+ int sublevels_up);
+extern Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
+ char *colname);
extern Node *colnameToVar(ParseState *pstate, char *colname);
extern Node *qualifiedNameToVar(ParseState *pstate,
char *schemaname,