@@ -31,21 +31,28 @@ IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
31
31
*
32
32
* We keep reserved and unreserved keywords in separate arrays. The
33
33
* reserved keywords are passed to the core scanner, so they will be
34
- * recognized before (and instead of) any variable name. Unreserved
35
- *words are checked for separately, after determining that the identifier
34
+ * recognized before (and instead of) any variable name. Unreserved words
35
+ * are checked for separately, usually after determining that the identifier
36
36
* isn't a known variable name. If plpgsql_IdentifierLookup is DECLARE then
37
37
* no variable names will be recognized, so the unreserved words always work.
38
38
* (Note in particular that this helps us avoid reserving keywords that are
39
39
* only needed in DECLARE sections.)
40
40
*
41
41
* In certain contexts it is desirable to prefer recognizing an unreserved
42
- * keyword over recognizing a variable name. Those cases are handled in
43
- * pl_gram.y using tok_is_keyword().
42
+ * keyword over recognizing a variable name. In particular, at the start
43
+ * of a statement we should prefer unreserved keywords unless the statement
44
+ * looks like an assignment (i.e., first token is followed by ':=' or '[').
45
+ * This rule allows most statement-introducing keywords to be kept unreserved.
46
+ * (We still have to reserve initial keywords that might follow a block
47
+ * label, unfortunately, since the method used to determine if we are at
48
+ * start of statement doesn't recognize such cases. We'd also have to
49
+ * reserve any keyword that could legitimately be followed by ':=' or '['.)
50
+ * Some additional cases are handled in pl_gram.y using tok_is_keyword().
44
51
*
45
- *For the most part, the reserved keywordsare those that start a PL/pgSQL
46
- *statement (and so would conflict with an assignment to a variable of the
47
- *same name). We also don't sweat it much about reserving keywords that
48
- *are reserved in the core grammar. Try to avoid reserving other words.
52
+ *We try to avoid reserving more keywordsthan we have to; but there's
53
+ *little point in not reserving a word if it's reserved in the core grammar.
54
+ *Currently, the following words are reserved here but not in the core:
55
+ *BEGIN BY DECLARE EXECUTE FOREACH IF LOOP STRICT WHILE
49
56
*/
50
57
51
58
/*
@@ -63,37 +70,20 @@ static const ScanKeyword reserved_keywords[] = {
63
70
PG_KEYWORD ("begin" ,K_BEGIN ,RESERVED_KEYWORD )
64
71
PG_KEYWORD ("by" ,K_BY ,RESERVED_KEYWORD )
65
72
PG_KEYWORD ("case" ,K_CASE ,RESERVED_KEYWORD )
66
- PG_KEYWORD ("close" ,K_CLOSE ,RESERVED_KEYWORD )
67
- PG_KEYWORD ("collate" ,K_COLLATE ,RESERVED_KEYWORD )
68
- PG_KEYWORD ("continue" ,K_CONTINUE ,RESERVED_KEYWORD )
69
73
PG_KEYWORD ("declare" ,K_DECLARE ,RESERVED_KEYWORD )
70
- PG_KEYWORD ("default" ,K_DEFAULT ,RESERVED_KEYWORD )
71
- PG_KEYWORD ("diagnostics" ,K_DIAGNOSTICS ,RESERVED_KEYWORD )
72
74
PG_KEYWORD ("else" ,K_ELSE ,RESERVED_KEYWORD )
73
- PG_KEYWORD ("elseif" ,K_ELSIF ,RESERVED_KEYWORD )
74
- PG_KEYWORD ("elsif" ,K_ELSIF ,RESERVED_KEYWORD )
75
75
PG_KEYWORD ("end" ,K_END ,RESERVED_KEYWORD )
76
- PG_KEYWORD ("exception" ,K_EXCEPTION ,RESERVED_KEYWORD )
77
76
PG_KEYWORD ("execute" ,K_EXECUTE ,RESERVED_KEYWORD )
78
- PG_KEYWORD ("exit" ,K_EXIT ,RESERVED_KEYWORD )
79
- PG_KEYWORD ("fetch" ,K_FETCH ,RESERVED_KEYWORD )
80
77
PG_KEYWORD ("for" ,K_FOR ,RESERVED_KEYWORD )
81
78
PG_KEYWORD ("foreach" ,K_FOREACH ,RESERVED_KEYWORD )
82
79
PG_KEYWORD ("from" ,K_FROM ,RESERVED_KEYWORD )
83
- PG_KEYWORD ("get" ,K_GET ,RESERVED_KEYWORD )
84
80
PG_KEYWORD ("if" ,K_IF ,RESERVED_KEYWORD )
85
81
PG_KEYWORD ("in" ,K_IN ,RESERVED_KEYWORD )
86
- PG_KEYWORD ("insert" ,K_INSERT ,RESERVED_KEYWORD )
87
82
PG_KEYWORD ("into" ,K_INTO ,RESERVED_KEYWORD )
88
83
PG_KEYWORD ("loop" ,K_LOOP ,RESERVED_KEYWORD )
89
- PG_KEYWORD ("move" ,K_MOVE ,RESERVED_KEYWORD )
90
84
PG_KEYWORD ("not" ,K_NOT ,RESERVED_KEYWORD )
91
85
PG_KEYWORD ("null" ,K_NULL ,RESERVED_KEYWORD )
92
- PG_KEYWORD ("open" ,K_OPEN ,RESERVED_KEYWORD )
93
86
PG_KEYWORD ("or" ,K_OR ,RESERVED_KEYWORD )
94
- PG_KEYWORD ("perform" ,K_PERFORM ,RESERVED_KEYWORD )
95
- PG_KEYWORD ("raise" ,K_RAISE ,RESERVED_KEYWORD )
96
- PG_KEYWORD ("return" ,K_RETURN ,RESERVED_KEYWORD )
97
87
PG_KEYWORD ("strict" ,K_STRICT ,RESERVED_KEYWORD )
98
88
PG_KEYWORD ("then" ,K_THEN ,RESERVED_KEYWORD )
99
89
PG_KEYWORD ("to" ,K_TO ,RESERVED_KEYWORD )
@@ -109,32 +99,47 @@ static const ScanKeyword unreserved_keywords[] = {
109
99
PG_KEYWORD ("alias" ,K_ALIAS ,UNRESERVED_KEYWORD )
110
100
PG_KEYWORD ("array" ,K_ARRAY ,UNRESERVED_KEYWORD )
111
101
PG_KEYWORD ("backward" ,K_BACKWARD ,UNRESERVED_KEYWORD )
102
+ PG_KEYWORD ("close" ,K_CLOSE ,UNRESERVED_KEYWORD )
103
+ PG_KEYWORD ("collate" ,K_COLLATE ,UNRESERVED_KEYWORD )
112
104
PG_KEYWORD ("column" ,K_COLUMN ,UNRESERVED_KEYWORD )
113
105
PG_KEYWORD ("column_name" ,K_COLUMN_NAME ,UNRESERVED_KEYWORD )
114
106
PG_KEYWORD ("constant" ,K_CONSTANT ,UNRESERVED_KEYWORD )
115
107
PG_KEYWORD ("constraint" ,K_CONSTRAINT ,UNRESERVED_KEYWORD )
116
108
PG_KEYWORD ("constraint_name" ,K_CONSTRAINT_NAME ,UNRESERVED_KEYWORD )
109
+ PG_KEYWORD ("continue" ,K_CONTINUE ,UNRESERVED_KEYWORD )
117
110
PG_KEYWORD ("current" ,K_CURRENT ,UNRESERVED_KEYWORD )
118
111
PG_KEYWORD ("cursor" ,K_CURSOR ,UNRESERVED_KEYWORD )
119
112
PG_KEYWORD ("datatype" ,K_DATATYPE ,UNRESERVED_KEYWORD )
120
113
PG_KEYWORD ("debug" ,K_DEBUG ,UNRESERVED_KEYWORD )
114
+ PG_KEYWORD ("default" ,K_DEFAULT ,UNRESERVED_KEYWORD )
121
115
PG_KEYWORD ("detail" ,K_DETAIL ,UNRESERVED_KEYWORD )
116
+ PG_KEYWORD ("diagnostics" ,K_DIAGNOSTICS ,UNRESERVED_KEYWORD )
122
117
PG_KEYWORD ("dump" ,K_DUMP ,UNRESERVED_KEYWORD )
118
+ PG_KEYWORD ("elseif" ,K_ELSIF ,UNRESERVED_KEYWORD )
119
+ PG_KEYWORD ("elsif" ,K_ELSIF ,UNRESERVED_KEYWORD )
123
120
PG_KEYWORD ("errcode" ,K_ERRCODE ,UNRESERVED_KEYWORD )
124
121
PG_KEYWORD ("error" ,K_ERROR ,UNRESERVED_KEYWORD )
122
+ PG_KEYWORD ("exception" ,K_EXCEPTION ,UNRESERVED_KEYWORD )
123
+ PG_KEYWORD ("exit" ,K_EXIT ,UNRESERVED_KEYWORD )
124
+ PG_KEYWORD ("fetch" ,K_FETCH ,UNRESERVED_KEYWORD )
125
125
PG_KEYWORD ("first" ,K_FIRST ,UNRESERVED_KEYWORD )
126
126
PG_KEYWORD ("forward" ,K_FORWARD ,UNRESERVED_KEYWORD )
127
+ PG_KEYWORD ("get" ,K_GET ,UNRESERVED_KEYWORD )
127
128
PG_KEYWORD ("hint" ,K_HINT ,UNRESERVED_KEYWORD )
128
129
PG_KEYWORD ("info" ,K_INFO ,UNRESERVED_KEYWORD )
130
+ PG_KEYWORD ("insert" ,K_INSERT ,UNRESERVED_KEYWORD )
129
131
PG_KEYWORD ("is" ,K_IS ,UNRESERVED_KEYWORD )
130
132
PG_KEYWORD ("last" ,K_LAST ,UNRESERVED_KEYWORD )
131
133
PG_KEYWORD ("log" ,K_LOG ,UNRESERVED_KEYWORD )
132
134
PG_KEYWORD ("message" ,K_MESSAGE ,UNRESERVED_KEYWORD )
133
135
PG_KEYWORD ("message_text" ,K_MESSAGE_TEXT ,UNRESERVED_KEYWORD )
136
+ PG_KEYWORD ("move" ,K_MOVE ,UNRESERVED_KEYWORD )
134
137
PG_KEYWORD ("next" ,K_NEXT ,UNRESERVED_KEYWORD )
135
138
PG_KEYWORD ("no" ,K_NO ,UNRESERVED_KEYWORD )
136
139
PG_KEYWORD ("notice" ,K_NOTICE ,UNRESERVED_KEYWORD )
140
+ PG_KEYWORD ("open" ,K_OPEN ,UNRESERVED_KEYWORD )
137
141
PG_KEYWORD ("option" ,K_OPTION ,UNRESERVED_KEYWORD )
142
+ PG_KEYWORD ("perform" ,K_PERFORM ,UNRESERVED_KEYWORD )
138
143
PG_KEYWORD ("pg_context" ,K_PG_CONTEXT ,UNRESERVED_KEYWORD )
139
144
PG_KEYWORD ("pg_datatype_name" ,K_PG_DATATYPE_NAME ,UNRESERVED_KEYWORD )
140
145
PG_KEYWORD ("pg_exception_context" ,K_PG_EXCEPTION_CONTEXT ,UNRESERVED_KEYWORD )
@@ -143,8 +148,10 @@ static const ScanKeyword unreserved_keywords[] = {
143
148
PG_KEYWORD ("print_strict_params" ,K_PRINT_STRICT_PARAMS ,UNRESERVED_KEYWORD )
144
149
PG_KEYWORD ("prior" ,K_PRIOR ,UNRESERVED_KEYWORD )
145
150
PG_KEYWORD ("query" ,K_QUERY ,UNRESERVED_KEYWORD )
151
+ PG_KEYWORD ("raise" ,K_RAISE ,UNRESERVED_KEYWORD )
146
152
PG_KEYWORD ("relative" ,K_RELATIVE ,UNRESERVED_KEYWORD )
147
153
PG_KEYWORD ("result_oid" ,K_RESULT_OID ,UNRESERVED_KEYWORD )
154
+ PG_KEYWORD ("return" ,K_RETURN ,UNRESERVED_KEYWORD )
148
155
PG_KEYWORD ("returned_sqlstate" ,K_RETURNED_SQLSTATE ,UNRESERVED_KEYWORD )
149
156
PG_KEYWORD ("reverse" ,K_REVERSE ,UNRESERVED_KEYWORD )
150
157
PG_KEYWORD ("row_count" ,K_ROW_COUNT ,UNRESERVED_KEYWORD )
@@ -166,6 +173,19 @@ static const ScanKeyword unreserved_keywords[] = {
166
173
167
174
static const int num_unreserved_keywords = lengthof (unreserved_keywords );
168
175
176
+ /*
177
+ * This macro must recognize all tokens that can immediately precede a
178
+ * PL/pgSQL executable statement (that is, proc_sect or proc_stmt in the
179
+ * grammar). Fortunately, there are not very many, so hard-coding in this
180
+ * fashion seems sufficient.
181
+ */
182
+ #define AT_STMT_START (prev_token ) \
183
+ ((prev_token) == ';' || \
184
+ (prev_token) == K_BEGIN || \
185
+ (prev_token) == K_THEN || \
186
+ (prev_token) == K_ELSE || \
187
+ (prev_token) == K_LOOP)
188
+
169
189
170
190
/* Auxiliary data about a token (other than the token type) */
171
191
typedef struct
@@ -192,6 +212,9 @@ static const char *scanorig;
192
212
/* Current token's length (corresponds to plpgsql_yylval and plpgsql_yylloc) */
193
213
static int plpgsql_yyleng ;
194
214
215
+ /* Current token's code (corresponds to plpgsql_yylval and plpgsql_yylloc) */
216
+ static int plpgsql_yytoken ;
217
+
195
218
/* Token pushback stack */
196
219
#define MAX_PUSHBACKS 4
197
220
@@ -315,31 +338,75 @@ plpgsql_yylex(void)
315
338
{
316
339
/* not A.B, so just process A */
317
340
push_back_token (tok2 ,& aux2 );
318
- if (plpgsql_parse_word (aux1 .lval .str ,
319
- core_yy .scanbuf + aux1 .lloc ,
320
- & aux1 .lval .wdatum ,
321
- & aux1 .lval .word ))
322
- tok1 = T_DATUM ;
323
- else if (!aux1 .lval .word .quoted &&
324
- (kw = ScanKeywordLookup (aux1 .lval .word .ident ,
325
- unreserved_keywords ,
326
- num_unreserved_keywords )))
341
+
342
+ /*
343
+ * If we are at start of statement, prefer unreserved keywords
344
+ * over variable names, unless the next token is assignment or
345
+ * '[', in which case prefer variable names. (Note we need not
346
+ * consider '.' as the next token; that case was handled above,
347
+ * and we always prefer variable names in that case.) If we are
348
+ * not at start of statement, always prefer variable names over
349
+ * unreserved keywords.
350
+ */
351
+ if (AT_STMT_START (plpgsql_yytoken )&&
352
+ !(tok2 == '=' || tok2 == COLON_EQUALS || tok2 == '[' ))
327
353
{
328
- aux1 .lval .keyword = kw -> name ;
329
- tok1 = kw -> value ;
354
+ /* try for unreserved keyword, then for variable name */
355
+ if (core_yy .scanbuf [aux1 .lloc ]!= '"' &&
356
+ (kw = ScanKeywordLookup (aux1 .lval .str ,
357
+ unreserved_keywords ,
358
+ num_unreserved_keywords )))
359
+ {
360
+ aux1 .lval .keyword = kw -> name ;
361
+ tok1 = kw -> value ;
362
+ }
363
+ else if (plpgsql_parse_word (aux1 .lval .str ,
364
+ core_yy .scanbuf + aux1 .lloc ,
365
+ & aux1 .lval .wdatum ,
366
+ & aux1 .lval .word ))
367
+ tok1 = T_DATUM ;
368
+ else
369
+ tok1 = T_WORD ;
330
370
}
331
371
else
332
- tok1 = T_WORD ;
372
+ {
373
+ /* try for variable name, then for unreserved keyword */
374
+ if (plpgsql_parse_word (aux1 .lval .str ,
375
+ core_yy .scanbuf + aux1 .lloc ,
376
+ & aux1 .lval .wdatum ,
377
+ & aux1 .lval .word ))
378
+ tok1 = T_DATUM ;
379
+ else if (!aux1 .lval .word .quoted &&
380
+ (kw = ScanKeywordLookup (aux1 .lval .word .ident ,
381
+ unreserved_keywords ,
382
+ num_unreserved_keywords )))
383
+ {
384
+ aux1 .lval .keyword = kw -> name ;
385
+ tok1 = kw -> value ;
386
+ }
387
+ else
388
+ tok1 = T_WORD ;
389
+ }
333
390
}
334
391
}
335
392
else
336
393
{
337
- /* Not a potential plpgsql variable name, just return the data */
394
+ /*
395
+ * Not a potential plpgsql variable name, just return the data.
396
+ *
397
+ * Note that we also come through here if the grammar pushed back a
398
+ * T_DATUM, T_CWORD, T_WORD, or unreserved-keyword token returned by a
399
+ * previous lookup cycle; thus, pushbacks do not incur extra lookup
400
+ * work, since we'll never do the above code twice for the same token.
401
+ * This property also makes it safe to rely on the old value of
402
+ * plpgsql_yytoken in the is-this-start-of-statement test above.
403
+ */
338
404
}
339
405
340
406
plpgsql_yylval = aux1 .lval ;
341
407
plpgsql_yylloc = aux1 .lloc ;
342
408
plpgsql_yyleng = aux1 .leng ;
409
+ plpgsql_yytoken = tok1 ;
343
410
return tok1 ;
344
411
}
345
412
@@ -645,6 +712,7 @@ plpgsql_scanner_init(const char *str)
645
712
646
713
/* Other setup */
647
714
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL ;
715
+ plpgsql_yytoken = 0 ;
648
716
649
717
num_pushbacks = 0 ;
650
718