4
4
* procedural language
5
5
*
6
6
* IDENTIFICATION
7
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.84 2006/02/12 06:03:38 momjian Exp $
7
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.85 2006/02/12 06:37:05 tgl Exp $
8
8
*
9
9
* This software is copyrighted by Jan Wieck - Hamburg.
10
10
*
@@ -54,13 +54,14 @@ static PLpgSQL_stmt *make_fetch_stmt(void);
54
54
static void check_assignable (PLpgSQL_datum *datum);
55
55
static PLpgSQL_row *read_into_scalar_list (const char *initial_name,
56
56
PLpgSQL_datum *initial_datum);
57
+ static PLpgSQL_row *make_scalar_list1 (const char *initial_name,
58
+ PLpgSQL_datum *initial_datum,
59
+ int lineno);
57
60
static void check_sql_expr (const char *stmt);
58
61
static void plpgsql_sql_error_callback (void *arg);
59
62
static void check_labels (const char *start_label,
60
63
const char *end_label);
61
- static PLpgSQL_row *make_scalar_list1 (const char *name,
62
- PLpgSQL_datum *variable);
63
-
64
+
64
65
%}
65
66
66
67
%union {
@@ -76,9 +77,9 @@ static PLpgSQL_row *make_scalar_list1(const char *name,
76
77
{
77
78
char *name;
78
79
int lineno;
80
+ PLpgSQL_datum *scalar;
79
81
PLpgSQL_rec *rec;
80
82
PLpgSQL_row *row;
81
- PLpgSQL_datum *scalar;
82
83
} forvariable;
83
84
struct
84
85
{
@@ -895,13 +896,14 @@ for_control :
895
896
}
896
897
else if ($2 .scalar)
897
898
{
898
- new ->row = make_scalar_list1($2 .name, $2 .scalar);
899
- check_assignable ((PLpgSQL_datum *) new->row);
899
+ /* convert single scalar to list */
900
+ new ->row = make_scalar_list1($2 .name, $2 .scalar, $2 .lineno);
901
+ /* no need for check_assignable */
900
902
}
901
903
else
902
904
{
903
- plpgsql_error_lineno = $1 ;
904
- yyerror (" loop variable of loop over rows must be a record, row, or scalar variable " );
905
+ plpgsql_error_lineno = $2 .lineno ;
906
+ yyerror (" loop variable of loop over rows must be a record or row variable or list of scalar variables " );
905
907
}
906
908
new ->query = expr;
907
909
@@ -950,24 +952,24 @@ for_control :
950
952
PLpgSQL_expr *expr2;
951
953
PLpgSQL_var *fvar;
952
954
PLpgSQL_stmt_fori *new ;
955
+ char *varname;
953
956
954
957
/* First expression is well-formed */
955
958
check_sql_expr (expr1->query);
956
959
957
960
expr2 = plpgsql_read_expression(K_LOOP, " LOOP" );
958
961
959
- /* T_SCALAR identifier waits for converting */
960
- if ($2 .scalar)
961
- {
962
- char *name;
963
- plpgsql_convert_ident ($2 .name, &name, 1 );
964
- pfree ($2 .name);
965
- $2 .name = name;
966
- }
962
+ /* should have had a single variable name */
963
+ plpgsql_error_lineno = $2 .lineno;
964
+ if ($2 .scalar && $2 .row)
965
+ ereport (ERROR,
966
+ (errcode(ERRCODE_SYNTAX_ERROR),
967
+ errmsg(" integer FOR loop must have just one target variable" )));
967
968
968
969
/* create loop's private variable */
970
+ plpgsql_convert_ident ($2 .name, &varname, 1 );
969
971
fvar = (PLpgSQL_var *)
970
- plpgsql_build_variable ($ 2 .name ,
972
+ plpgsql_build_variable (varname ,
971
973
$2 .lineno,
972
974
plpgsql_build_datatype (INT4OID,
973
975
-1 ),
@@ -1021,13 +1023,14 @@ for_control :
1021
1023
}
1022
1024
else if ($2 .scalar)
1023
1025
{
1024
- new ->row = make_scalar_list1($2 .name, $2 .scalar);
1025
- check_assignable ((PLpgSQL_datum *) new->row);
1026
+ /* convert single scalar to list */
1027
+ new ->row = make_scalar_list1($2 .name, $2 .scalar, $2 .lineno);
1028
+ /* no need for check_assignable */
1026
1029
}
1027
1030
else
1028
1031
{
1029
- plpgsql_error_lineno = $1 ;
1030
- yyerror (" loop variable of loop over rows must be record, row, or scalar variable " );
1032
+ plpgsql_error_lineno = $2 .lineno ;
1033
+ yyerror (" loop variable of loop over rows must be a record or row variable or list of scalar variables " );
1031
1034
}
1032
1035
1033
1036
new ->query = expr1;
@@ -1047,55 +1050,63 @@ for_control :
1047
1050
* if any, because that's what we need for the loop-over-query case. Note
1048
1051
* that we must NOT apply check_assignable() or any other semantic check
1049
1052
* until we know what's what.
1053
+ *
1054
+ * However, if we see a comma-separated list of names, we know that it
1055
+ * can't be an integer FOR loop and so it's OK to check the variables
1056
+ * immediately. In particular, for T_WORD followed by comma, we should
1057
+ * complain that the name is not known rather than say it's a syntax error.
1058
+ * Note that the non-error result of this case sets *both* $$.scalar and
1059
+ * $$.row; see the for_control production.
1050
1060
*/
1051
1061
for_variable : T_SCALAR
1052
- {
1053
- int tok;
1054
- char *name;
1055
-
1056
- name = pstrdup(yytext);
1057
- $$ .scalar = yylval.scalar;
1058
- $$ .lineno = plpgsql_scanner_lineno();
1062
+ {
1063
+ int tok;
1059
1064
1060
- if ((tok = yylex ()) == ' ,' )
1061
- {
1062
- plpgsql_push_back_token (tok);
1063
- $$ .name = NULL ;
1064
- $$ .row = read_into_scalar_list(name, $$ .scalar);
1065
- $$ .rec = NULL ;
1066
- $$ .scalar = NULL ;
1067
-
1068
- pfree (name);
1069
- }
1070
- else
1071
- {
1072
- plpgsql_push_back_token (tok);
1073
- $$ .name = name;
1074
- $$ .row = NULL ;
1075
- $$ .rec = NULL ;
1076
- }
1065
+ $$ .name = pstrdup(yytext);
1066
+ $$ .lineno = plpgsql_scanner_lineno();
1067
+ $$ .scalar = yylval.scalar;
1068
+ $$ .rec = NULL ;
1069
+ $$ .row = NULL ;
1070
+ /* check for comma-separated list */
1071
+ tok = yylex ();
1072
+ plpgsql_push_back_token (tok);
1073
+ if (tok == ' ,' )
1074
+ $$ .row = read_into_scalar_list($$ .name, $$ .scalar);
1077
1075
}
1078
1076
| T_WORD
1079
1077
{
1080
- char *name ;
1078
+ int tok ;
1081
1079
1082
- plpgsql_convert_ident (yytext, &name, 1 );
1083
- $$ .name = name;
1080
+ $$ .name = pstrdup(yytext);
1084
1081
$$ .lineno = plpgsql_scanner_lineno();
1082
+ $$ .scalar = NULL ;
1085
1083
$$ .rec = NULL ;
1086
1084
$$ .row = NULL ;
1085
+ /* check for comma-separated list */
1086
+ tok = yylex ();
1087
+ plpgsql_push_back_token (tok);
1088
+ if (tok == ' ,' )
1089
+ {
1090
+ plpgsql_error_lineno = $$ .lineno;
1091
+ ereport (ERROR,
1092
+ (errcode(ERRCODE_SYNTAX_ERROR),
1093
+ errmsg(" \" %s\" is not a scalar variable" ,
1094
+ $$.name)));
1095
+ }
1087
1096
}
1088
1097
| T_RECORD
1089
1098
{
1090
- $$ .name = NULL ;
1099
+ $$ .name = pstrdup(yytext) ;
1091
1100
$$ .lineno = plpgsql_scanner_lineno();
1101
+ $$ .scalar = NULL ;
1092
1102
$$ .rec = yylval.rec;
1093
1103
$$ .row = NULL ;
1094
1104
}
1095
1105
| T_ROW
1096
1106
{
1097
- $$ .name = NULL ;
1107
+ $$ .name = pstrdup(yytext) ;
1098
1108
$$ .lineno = plpgsql_scanner_lineno();
1109
+ $$ .scalar = NULL ;
1099
1110
$$ .row = yylval.row;
1100
1111
$$ .rec = NULL ;
1101
1112
}
@@ -2121,30 +2132,6 @@ make_fetch_stmt(void)
2121
2132
}
2122
2133
2123
2134
2124
- static PLpgSQL_row *
2125
- make_scalar_list1 (const char *name,
2126
- PLpgSQL_datum *variable)
2127
- {
2128
- PLpgSQL_row *row;
2129
- check_assignable (variable);
2130
-
2131
- row = palloc (sizeof (PLpgSQL_row));
2132
- row->dtype = PLPGSQL_DTYPE_ROW;
2133
- row->refname = pstrdup (" *internal*" );
2134
- row->lineno = plpgsql_scanner_lineno ();
2135
- row->rowtupdesc = NULL ;
2136
- row->nfields = 1 ;
2137
- row->fieldnames = palloc (sizeof (char *) * 1 );
2138
- row->varnos = palloc (sizeof (int ) * 1 );
2139
- row->fieldnames [0 ] = pstrdup (name);
2140
- row->varnos [0 ] = variable->dno ;
2141
-
2142
- plpgsql_adddatum ((PLpgSQL_datum *)row);
2143
-
2144
- return row;
2145
- }
2146
-
2147
-
2148
2135
static void
2149
2136
check_assignable (PLpgSQL_datum *datum)
2150
2137
{
@@ -2256,6 +2243,37 @@ read_into_scalar_list(const char *initial_name,
2256
2243
return row;
2257
2244
}
2258
2245
2246
+ /*
2247
+ * Convert a single scalar into a "row" list. This is exactly
2248
+ * like read_into_scalar_list except we never consume any input.
2249
+ * In fact, since this can be invoked long after the source
2250
+ * input was actually read, the lineno has to be passed in.
2251
+ */
2252
+ static PLpgSQL_row *
2253
+ make_scalar_list1 (const char *initial_name,
2254
+ PLpgSQL_datum *initial_datum,
2255
+ int lineno)
2256
+ {
2257
+ PLpgSQL_row *row;
2258
+
2259
+ check_assignable (initial_datum);
2260
+
2261
+ row = palloc (sizeof (PLpgSQL_row));
2262
+ row->dtype = PLPGSQL_DTYPE_ROW;
2263
+ row->refname = pstrdup (" *internal*" );
2264
+ row->lineno = lineno;
2265
+ row->rowtupdesc = NULL ;
2266
+ row->nfields = 1 ;
2267
+ row->fieldnames = palloc (sizeof (char *));
2268
+ row->varnos = palloc (sizeof (int ));
2269
+ row->fieldnames [0 ] = pstrdup (initial_name);
2270
+ row->varnos [0 ] = initial_datum->dno ;
2271
+
2272
+ plpgsql_adddatum ((PLpgSQL_datum *)row);
2273
+
2274
+ return row;
2275
+ }
2276
+
2259
2277
/*
2260
2278
* When the PL/PgSQL parser expects to see a SQL statement, it is very
2261
2279
* liberal in what it accepts; for example, we often assume an
0 commit comments