8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -40,6 +40,8 @@ bool Transform_null_equals = false;
40
40
static Node * typecast_expression (ParseState * pstate , Node * expr ,
41
41
TypeName * typename );
42
42
static Node * transformColumnRef (ParseState * pstate , ColumnRef * cref );
43
+ static Node * transformWholeRowRef (ParseState * pstate , char * schemaname ,
44
+ char * relname );
43
45
static Node * transformIndirection (ParseState * pstate , Node * basenode ,
44
46
List * indirection );
45
47
@@ -932,34 +934,29 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
932
934
{
933
935
int numnames = length (cref -> fields );
934
936
Node * node ;
935
- RangeVar * rv ;
936
937
int levels_up ;
937
938
938
939
/*----------
939
940
* The allowed syntaxes are:
940
941
*
941
942
* 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
944
945
* column or function name (trying column name first).
945
946
* A.B.C schema A, table B, col or func name C.
946
947
* 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.
948
949
* A.B.* whole-row value of table B in schema A.
949
950
* A.B.C.* whole-row value of table C in schema B in catalog A.
950
951
*
951
952
* We do not need to cope with bare "*"; that will only be accepted by
952
953
* 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.
954
957
*
955
958
* Currently, if a catalog name is given then it must equal the current
956
959
* 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.)
963
960
*----------
964
961
*/
965
962
switch (numnames )
@@ -1001,16 +998,12 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1001
998
if (cref -> indirection == NIL &&
1002
999
refnameRangeTblEntry (pstate , NULL , name ,
1003
1000
& 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 );
1010
1002
else
1011
1003
ereport (ERROR ,
1012
1004
(errcode (ERRCODE_UNDEFINED_COLUMN ),
1013
- errmsg ("column \"%s\" does not exist" , name )));
1005
+ errmsg ("column \"%s\" does not exist" ,
1006
+ name )));
1014
1007
}
1015
1008
break ;
1016
1009
}
@@ -1022,10 +1015,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1022
1015
/* Whole-row reference? */
1023
1016
if (strcmp (name2 , "*" ) == 0 )
1024
1017
{
1025
- rv = makeNode (RangeVar );
1026
- rv -> relname = name1 ;
1027
- rv -> inhOpt = INH_DEFAULT ;
1028
- node = (Node * ) rv ;
1018
+ node = transformWholeRowRef (pstate , NULL , name1 );
1029
1019
break ;
1030
1020
}
1031
1021
@@ -1038,12 +1028,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1038
1028
* try it as a function call. Here, we will create an
1039
1029
* implicit RTE for tables not already entered.
1040
1030
*/
1041
- rv = makeNode (RangeVar );
1042
- rv -> relname = name1 ;
1043
- rv -> inhOpt = INH_DEFAULT ;
1031
+ node = transformWholeRowRef (pstate , NULL , name1 );
1044
1032
node = ParseFuncOrColumn (pstate ,
1045
1033
makeList1 (makeString (name2 )),
1046
- makeList1 (rv ),
1034
+ makeList1 (node ),
1047
1035
false, false, true);
1048
1036
}
1049
1037
break ;
@@ -1057,11 +1045,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1057
1045
/* Whole-row reference? */
1058
1046
if (strcmp (name3 , "*" ) == 0 )
1059
1047
{
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 );
1065
1049
break ;
1066
1050
}
1067
1051
@@ -1070,13 +1054,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1070
1054
if (node == NULL )
1071
1055
{
1072
1056
/* 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 );
1077
1058
node = ParseFuncOrColumn (pstate ,
1078
1059
makeList1 (makeString (name3 )),
1079
- makeList1 (rv ),
1060
+ makeList1 (node ),
1080
1061
false, false, true);
1081
1062
}
1082
1063
break ;
@@ -1100,11 +1081,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1100
1081
/* Whole-row reference? */
1101
1082
if (strcmp (name4 , "*" ) == 0 )
1102
1083
{
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 );
1108
1085
break ;
1109
1086
}
1110
1087
@@ -1113,13 +1090,10 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1113
1090
if (node == NULL )
1114
1091
{
1115
1092
/* 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 );
1120
1094
node = ParseFuncOrColumn (pstate ,
1121
1095
makeList1 (makeString (name4 )),
1122
- makeList1 (rv ),
1096
+ makeList1 (node ),
1123
1097
false, false, true);
1124
1098
}
1125
1099
break ;
@@ -1136,6 +1110,99 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
1136
1110
return transformIndirection (pstate , node , cref -> indirection );
1137
1111
}
1138
1112
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
+
1139
1206
/*
1140
1207
* exprType -
1141
1208
* returns the Oid of the type of the expression. (Used for typechecking.)
@@ -1294,19 +1361,6 @@ exprType(Node *expr)
1294
1361
case T_SetToDefault :
1295
1362
type = ((SetToDefault * ) expr )-> typeId ;
1296
1363
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 ;
1310
1364
default :
1311
1365
elog (ERROR , "unrecognized node type: %d" , (int ) nodeTag (expr ));
1312
1366
type = InvalidOid ; /* keep compiler quiet */
0 commit comments