Thanks to visit codestin.com
Credit goes to github.com

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)