Skip to content

Commit 27a4f06

Browse files
committed
Get rid of crocky use of RangeVar nodes in parser to represent partially
transformed whole-row variables. Cleaner to use regular whole-row Vars.
1 parent 94d8da8 commit 27a4f06

File tree

6 files changed

+227
-293
lines changed

6 files changed

+227
-293
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.167 2004/03/24 22:40:28 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.168 2004/04/02 19:06:57 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -2550,16 +2550,6 @@ expression_tree_walker(Node *node,
25502550
return true;
25512551
}
25522552
break;
2553-
case T_RangeVar:
2554-
/*
2555-
* Give a useful complaint if someone uses a bare relation name
2556-
* in an expression (see comments in transformColumnRef()).
2557-
*/
2558-
ereport(ERROR,
2559-
(errcode(ERRCODE_SYNTAX_ERROR),
2560-
errmsg("relation reference \"%s\" cannot be used in an expression",
2561-
((RangeVar *) node)->relname)));
2562-
break;
25632553
default:
25642554
elog(ERROR, "unrecognized node type: %d",
25652555
(int) nodeTag(node));
@@ -3031,16 +3021,6 @@ expression_tree_mutator(Node *node,
30313021
return (Node *) newnode;
30323022
}
30333023
break;
3034-
case T_RangeVar:
3035-
/*
3036-
* Give a useful complaint if someone uses a bare relation name
3037-
* in an expression (see comments in transformColumnRef()).
3038-
*/
3039-
ereport(ERROR,
3040-
(errcode(ERRCODE_SYNTAX_ERROR),
3041-
errmsg("relation reference \"%s\" cannot be used in an expression",
3042-
((RangeVar *) node)->relname)));
3043-
break;
30443024
default:
30453025
elog(ERROR, "unrecognized node type: %d",
30463026
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 114 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.167 2004/03/24 22:40:29 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.168 2004/04/02 19:06:58 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -40,6 +40,8 @@ bool Transform_null_equals = false;
4040
static Node *typecast_expression(ParseState *pstate, Node *expr,
4141
TypeName *typename);
4242
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
43+
static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
44+
char *relname);
4345
static Node *transformIndirection(ParseState *pstate, Node *basenode,
4446
List *indirection);
4547

@@ -932,34 +934,29 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
932934
{
933935
int numnames = length(cref->fields);
934936
Node *node;
935-
RangeVar *rv;
936937
int levels_up;
937938

938939
/*----------
939940
* The allowed syntaxes are:
940941
*
941942
* A First try to resolve as unqualified column name;
942-
* if no luck, try to resolve as unqual. table name (A.*).
943-
* A.B A is an unqual. table name; B is either a
943+
* if no luck, try to resolve as unqualified table name (A.*).
944+
* A.B A is an unqualified table name; B is either a
944945
* column or function name (trying column name first).
945946
* A.B.C schema A, table B, col or func name C.
946947
* A.B.C.D catalog A, schema B, table C, col or func D.
947-
* A.* A is an unqual. table name; means whole-row value.
948+
* A.* A is an unqualified table name; means whole-row value.
948949
* A.B.* whole-row value of table B in schema A.
949950
* A.B.C.* whole-row value of table C in schema B in catalog A.
950951
*
951952
* We do not need to cope with bare "*"; that will only be accepted by
952953
* the grammar at the top level of a SELECT list, and transformTargetList
953-
* will take care of it before it ever gets here.
954+
* will take care of it before it ever gets here. Also, "A.*" etc will
955+
* be expanded by transformTargetList if they appear at SELECT top level,
956+
* so here we are only going to see them as function or operator inputs.
954957
*
955958
* Currently, if a catalog name is given then it must equal the current
956959
* database name; we check it here and then discard it.
957-
*
958-
* For whole-row references, the result is an untransformed RangeVar,
959-
* which will work as the argument to a function call, but not in any
960-
* other context at present. (We could instead coerce to a whole-row Var,
961-
* but that will fail for subselect and join RTEs, because there is no
962-
* pg_type entry for their rowtypes.)
963960
*----------
964961
*/
965962
switch (numnames)
@@ -1001,16 +998,12 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1001998
if (cref->indirection == NIL &&
1002999
refnameRangeTblEntry(pstate, NULL, name,
10031000
&levels_up) != NULL)
1004-
{
1005-
rv = makeNode(RangeVar);
1006-
rv->relname = name;
1007-
rv->inhOpt = INH_DEFAULT;
1008-
node = (Node *) rv;
1009-
}
1001+
node = transformWholeRowRef(pstate, NULL, name);
10101002
else
10111003
ereport(ERROR,
10121004
(errcode(ERRCODE_UNDEFINED_COLUMN),
1013-
errmsg("column \"%s\" does not exist", name)));
1005+
errmsg("column \"%s\" does not exist",
1006+
name)));
10141007
}
10151008
break;
10161009
}
@@ -1022,10 +1015,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
10221015
/* Whole-row reference? */
10231016
if (strcmp(name2, "*") == 0)
10241017
{
1025-
rv = makeNode(RangeVar);
1026-
rv->relname = name1;
1027-
rv->inhOpt = INH_DEFAULT;
1028-
node = (Node *) rv;
1018+
node = transformWholeRowRef(pstate, NULL, name1);
10291019
break;
10301020
}
10311021

@@ -1038,12 +1028,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
10381028
* try it as a function call. Here, we will create an
10391029
* implicit RTE for tables not already entered.
10401030
*/
1041-
rv = makeNode(RangeVar);
1042-
rv->relname = name1;
1043-
rv->inhOpt = INH_DEFAULT;
1031+
node = transformWholeRowRef(pstate, NULL, name1);
10441032
node = ParseFuncOrColumn(pstate,
10451033
makeList1(makeString(name2)),
1046-
makeList1(rv),
1034+
makeList1(node),
10471035
false, false, true);
10481036
}
10491037
break;
@@ -1057,11 +1045,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
10571045
/* Whole-row reference? */
10581046
if (strcmp(name3, "*") == 0)
10591047
{
1060-
rv = makeNode(RangeVar);
1061-
rv->schemaname = name1;
1062-
rv->relname = name2;
1063-
rv->inhOpt = INH_DEFAULT;
1064-
node = (Node *) rv;
1048+
node = transformWholeRowRef(pstate, name1, name2);
10651049
break;
10661050
}
10671051

@@ -1070,13 +1054,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
10701054
if (node == NULL)
10711055
{
10721056
/* Try it as a function call */
1073-
rv = makeNode(RangeVar);
1074-
rv->schemaname = name1;
1075-
rv->relname = name2;
1076-
rv->inhOpt = INH_DEFAULT;
1057+
node = transformWholeRowRef(pstate, name1, name2);
10771058
node = ParseFuncOrColumn(pstate,
10781059
makeList1(makeString(name3)),
1079-
makeList1(rv),
1060+
makeList1(node),
10801061
false, false, true);
10811062
}
10821063
break;
@@ -1100,11 +1081,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
11001081
/* Whole-row reference? */
11011082
if (strcmp(name4, "*") == 0)
11021083
{
1103-
rv = makeNode(RangeVar);
1104-
rv->schemaname = name2;
1105-
rv->relname = name3;
1106-
rv->inhOpt = INH_DEFAULT;
1107-
node = (Node *) rv;
1084+
node = transformWholeRowRef(pstate, name2, name3);
11081085
break;
11091086
}
11101087

@@ -1113,13 +1090,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
11131090
if (node == NULL)
11141091
{
11151092
/* Try it as a function call */
1116-
rv = makeNode(RangeVar);
1117-
rv->schemaname = name2;
1118-
rv->relname = name3;
1119-
rv->inhOpt = INH_DEFAULT;
1093+
node = transformWholeRowRef(pstate, name2, name3);
11201094
node = ParseFuncOrColumn(pstate,
11211095
makeList1(makeString(name4)),
1122-
makeList1(rv),
1096+
makeList1(node),
11231097
false, false, true);
11241098
}
11251099
break;
@@ -1136,6 +1110,99 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
11361110
return transformIndirection(pstate, node, cref->indirection);
11371111
}
11381112

1113+
/*
1114+
* Construct a whole-row reference to represent the notation "relation.*".
1115+
*
1116+
* In simple cases, this will be a Var with varno set to the correct range
1117+
* table entry, and varattno == 0 to signal that it references the whole
1118+
* tuple. (Use of zero here is unclean, since it could easily be confused
1119+
* with error cases, but it's not worth changing now.) The vartype indicates
1120+
* a rowtype; either a named composite type, or RECORD.
1121+
*
1122+
* We also need the ability to build a row-constructor expression, but the
1123+
* infrastructure for that doesn't exist just yet.
1124+
*/
1125+
static Node *
1126+
transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname)
1127+
{
1128+
Node *result;
1129+
RangeTblEntry *rte;
1130+
int vnum;
1131+
int sublevels_up;
1132+
Oid toid;
1133+
1134+
/* Look up the referenced RTE, creating it if needed */
1135+
1136+
rte = refnameRangeTblEntry(pstate, schemaname, relname,
1137+
&sublevels_up);
1138+
1139+
if (rte == NULL)
1140+
rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname));
1141+
1142+
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
1143+
1144+
/* Build the appropriate referencing node */
1145+
1146+
switch (rte->rtekind)
1147+
{
1148+
case RTE_RELATION:
1149+
/* relation: the rowtype is a named composite type */
1150+
toid = get_rel_type_id(rte->relid);
1151+
if (!OidIsValid(toid))
1152+
elog(ERROR, "could not find type OID for relation %u",
1153+
rte->relid);
1154+
result = (Node *) makeVar(vnum,
1155+
InvalidAttrNumber,
1156+
toid,
1157+
-1,
1158+
sublevels_up);
1159+
break;
1160+
case RTE_FUNCTION:
1161+
toid = exprType(rte->funcexpr);
1162+
if (toid == RECORDOID || get_typtype(toid) == 'c')
1163+
{
1164+
/* func returns composite; same as relation case */
1165+
result = (Node *) makeVar(vnum,
1166+
InvalidAttrNumber,
1167+
toid,
1168+
-1,
1169+
sublevels_up);
1170+
}
1171+
else
1172+
{
1173+
/*
1174+
* func returns scalar; instead of making a whole-row Var,
1175+
* just reference the function's scalar output. (XXX this
1176+
* seems a tad inconsistent, especially if "f.*" was
1177+
* explicitly written ...)
1178+
*/
1179+
result = (Node *) makeVar(vnum,
1180+
1,
1181+
toid,
1182+
-1,
1183+
sublevels_up);
1184+
}
1185+
break;
1186+
default:
1187+
/*
1188+
* RTE is a join or subselect. For the moment we represent this
1189+
* as a whole-row Var of RECORD type, but this will not actually
1190+
* work; need a row-constructor expression instead.
1191+
*
1192+
* XXX after fixing, be sure that unknown_attribute still
1193+
* does the right thing.
1194+
*/
1195+
result = (Node *) makeVar(vnum,
1196+
InvalidAttrNumber,
1197+
RECORDOID,
1198+
-1,
1199+
sublevels_up);
1200+
break;
1201+
}
1202+
1203+
return result;
1204+
}
1205+
11391206
/*
11401207
* exprType -
11411208
* returns the Oid of the type of the expression. (Used for typechecking.)
@@ -1294,19 +1361,6 @@ exprType(Node *expr)
12941361
case T_SetToDefault:
12951362
type = ((SetToDefault *) expr)->typeId;
12961363
break;
1297-
case T_RangeVar:
1298-
1299-
/*
1300-
* If someone uses a bare relation name in an expression, we
1301-
* will likely first notice a problem here (see comments in
1302-
* transformColumnRef()). Issue an appropriate error message.
1303-
*/
1304-
ereport(ERROR,
1305-
(errcode(ERRCODE_SYNTAX_ERROR),
1306-
errmsg("relation reference \"%s\" cannot be used in an expression",
1307-
((RangeVar *) expr)->relname)));
1308-
type = InvalidOid; /* keep compiler quiet */
1309-
break;
13101364
default:
13111365
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
13121366
type = InvalidOid; /* keep compiler quiet */

0 commit comments

Comments
 (0)