Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit01f7d29

Browse files
committed
Improve plpgsql's handling of record field references by forcing all potential
field references in SQL expressions to have RECFIELD datum-array entries atparse time. If it turns out that the reference is actually to a SQL column,the RECFIELD entry is useless, but it costs little. This allows us to get ridof the previous use of FieldSelect applied to a whole-row Param for the recordvariable; which was not only slower than a direct RECFIELD reference, butfailed for references to system columns of a trigger's NEW or OLD record.Per report and fix suggestion from Dean Rasheed.
1 parentf537e7d commit01f7d29

File tree

4 files changed

+77
-74
lines changed

4 files changed

+77
-74
lines changed

‎src/pl/plpgsql/src/gram.y

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.137 2010/01/02 16:58:12 momjian Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.138 2010/01/10 17:15:18 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -369,21 +369,21 @@ pl_block: decl_sect K_BEGIN proc_sect exception_sect K_END opt_label
369369
decl_sect:opt_block_label
370370
{
371371
/* done with decls, so resume identifier lookup*/
372-
plpgsql_LookupIdentifiers =true;
372+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_NORMAL;
373373
$$.label =$1;
374374
$$.n_initvars =0;
375375
$$.initvarnos =NULL;
376376
}
377377
|opt_block_labeldecl_start
378378
{
379-
plpgsql_LookupIdentifiers =true;
379+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_NORMAL;
380380
$$.label =$1;
381381
$$.n_initvars =0;
382382
$$.initvarnos =NULL;
383383
}
384384
|opt_block_labeldecl_startdecl_stmts
385385
{
386-
plpgsql_LookupIdentifiers =true;
386+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_NORMAL;
387387
if ($3 !=NULL)
388388
$$.label =$3;
389389
else
@@ -401,7 +401,7 @@ decl_start: K_DECLARE
401401
* Disable scanner lookup of identifiers while
402402
* we process the decl_stmts
403403
*/
404-
plpgsql_LookupIdentifiers =false;
404+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_DECLARE;
405405
}
406406
;
407407

@@ -2121,17 +2121,17 @@ read_sql_construct(int until,
21212121
{
21222122
inttok;
21232123
StringInfoDatads;
2124-
boolsave_LookupIdentifiers;
2124+
IdentifierLookupsave_IdentifierLookup;
21252125
intstartlocation = -1;
21262126
intparenlevel = 0;
21272127
PLpgSQL_expr*expr;
21282128

21292129
initStringInfo(&ds);
21302130
appendStringInfoString(&ds, sqlstart);
21312131

2132-
/*no need to lookup identifiers within the SQL text*/
2133-
save_LookupIdentifiers =plpgsql_LookupIdentifiers;
2134-
plpgsql_LookupIdentifiers =false;
2132+
/*special lookup mode for identifiers within the SQL text*/
2133+
save_IdentifierLookup =plpgsql_IdentifierLookup;
2134+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_EXPR;
21352135

21362136
for (;;)
21372137
{
@@ -2176,7 +2176,7 @@ read_sql_construct(int until,
21762176
}
21772177
}
21782178

2179-
plpgsql_LookupIdentifiers =save_LookupIdentifiers;
2179+
plpgsql_IdentifierLookup =save_IdentifierLookup;
21802180

21812181
if (startloc)
21822182
*startloc = startlocation;
@@ -2221,8 +2221,8 @@ read_datatype(int tok)
22212221
PLpgSQL_type*result;
22222222
intparenlevel = 0;
22232223

2224-
/* Shouldalways be calledwith LookupIdentifiers off*/
2225-
Assert(!plpgsql_LookupIdentifiers);
2224+
/* Shouldonly be calledwhile parsing DECLARE sections*/
2225+
Assert(plpgsql_IdentifierLookup == IDENTIFIER_LOOKUP_DECLARE);
22262226

22272227
/* Often there will be a lookahead token, but if not, get one*/
22282228
if (tok == YYEMPTY)
@@ -2327,7 +2327,7 @@ static PLpgSQL_stmt *
23272327
make_execsql_stmt(int firsttoken, int location)
23282328
{
23292329
StringInfoDatads;
2330-
boolsave_LookupIdentifiers;
2330+
IdentifierLookupsave_IdentifierLookup;
23312331
PLpgSQL_stmt_execsql *execsql;
23322332
PLpgSQL_expr*expr;
23332333
PLpgSQL_row*row = NULL;
@@ -2341,9 +2341,9 @@ make_execsql_stmt(int firsttoken, int location)
23412341

23422342
initStringInfo(&ds);
23432343

2344-
/*no need to lookup identifiers within the SQL text*/
2345-
save_LookupIdentifiers =plpgsql_LookupIdentifiers;
2346-
plpgsql_LookupIdentifiers =false;
2344+
/*special lookup mode for identifiers within the SQL text*/
2345+
save_IdentifierLookup =plpgsql_IdentifierLookup;
2346+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_EXPR;
23472347

23482348
/*
23492349
* We have to special-case the sequence INSERT INTO, because we don't want
@@ -2371,13 +2371,13 @@ make_execsql_stmt(int firsttoken, int location)
23712371
yyerror("INTO specified more than once");
23722372
have_into = true;
23732373
into_start_loc = yylloc;
2374-
plpgsql_LookupIdentifiers =true;
2374+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_NORMAL;
23752375
read_into_target(&rec, &row, &have_strict);
2376-
plpgsql_LookupIdentifiers =false;
2376+
plpgsql_IdentifierLookup =IDENTIFIER_LOOKUP_EXPR;
23772377
}
23782378
}
23792379

2380-
plpgsql_LookupIdentifiers =save_LookupIdentifiers;
2380+
plpgsql_IdentifierLookup =save_IdentifierLookup;
23812381

23822382
if (have_into)
23832383
{

‎src/pl/plpgsql/src/pl_comp.c

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.147 2010/01/02 16:58:12 momjian Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.148 2010/01/10 17:15:18 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1132,11 +1132,7 @@ resolve_column_ref(PLpgSQL_expr *expr, ColumnRef *cref)
11321132
returnmake_datum_param(expr,nse->itemno,cref->location);
11331133
if (nnames==nnames_field)
11341134
{
1135-
/* colname must be a field in this record */
1136-
PLpgSQL_rec*rec= (PLpgSQL_rec*)estate->datums[nse->itemno];
1137-
FieldSelect*fselect;
1138-
Oidfldtype;
1139-
intfldno;
1135+
/* colname could be a field in this record */
11401136
inti;
11411137

11421138
/* search for a datum referencing this field */
@@ -1153,28 +1149,19 @@ resolve_column_ref(PLpgSQL_expr *expr, ColumnRef *cref)
11531149
}
11541150

11551151
/*
1156-
* Wecan't readily add a recfield datumat runtime, so
1157-
*instead build a whole-row Param and a FieldSelect node.
1158-
*This is a bit less efficient, so we prefer the recfield
1159-
*way when possible.
1152+
* Weshould not get here, because a RECFIELD datumshould
1153+
*have been built at parse time for every possible qualified
1154+
*reference to fields of this record. But if we do, fall
1155+
*out and return NULL.
11601156
*/
1161-
fldtype=exec_get_rec_fieldtype(rec,colname,
1162-
&fldno);
1163-
fselect=makeNode(FieldSelect);
1164-
fselect->arg= (Expr*)make_datum_param(expr,nse->itemno,
1165-
cref->location);
1166-
fselect->fieldnum=fldno;
1167-
fselect->resulttype=fldtype;
1168-
fselect->resulttypmod=-1;
1169-
return (Node*)fselect;
11701157
}
11711158
break;
11721159
casePLPGSQL_NSTYPE_ROW:
11731160
if (nnames==nnames_wholerow)
11741161
returnmake_datum_param(expr,nse->itemno,cref->location);
11751162
if (nnames==nnames_field)
11761163
{
1177-
/* colnamemust be a field in this row */
1164+
/* colnamecould be a field in this row */
11781165
PLpgSQL_row*row= (PLpgSQL_row*)estate->datums[nse->itemno];
11791166
inti;
11801167

@@ -1187,10 +1174,7 @@ resolve_column_ref(PLpgSQL_expr *expr, ColumnRef *cref)
11871174
cref->location);
11881175
}
11891176
}
1190-
ereport(ERROR,
1191-
(errcode(ERRCODE_UNDEFINED_COLUMN),
1192-
errmsg("row \"%s\" has no field \"%s\"",
1193-
row->refname,colname)));
1177+
/* Not found, so return NULL */
11941178
}
11951179
break;
11961180
default:
@@ -1257,8 +1241,12 @@ plpgsql_parse_word(char *word1, const char *yytxt,
12571241
{
12581242
PLpgSQL_nsitem*ns;
12591243

1260-
/* No lookup if disabled */
1261-
if (plpgsql_LookupIdentifiers)
1244+
/*
1245+
* We should do nothing in DECLARE sections. In SQL expressions, there's
1246+
* no need to do anything either --- lookup will happen when the expression
1247+
* is compiled.
1248+
*/
1249+
if (plpgsql_IdentifierLookup==IDENTIFIER_LOOKUP_NORMAL)
12621250
{
12631251
/*
12641252
* Do a lookup in the current namespace stack
@@ -1281,6 +1269,7 @@ plpgsql_parse_word(char *word1, const char *yytxt,
12811269
return true;
12821270

12831271
default:
1272+
/* plpgsql_ns_lookup should never return anything else */
12841273
elog(ERROR,"unrecognized plpgsql itemtype: %d",
12851274
ns->itemtype);
12861275
}
@@ -1313,8 +1302,12 @@ plpgsql_parse_dblword(char *word1, char *word2,
13131302
idents=list_make2(makeString(word1),
13141303
makeString(word2));
13151304

1316-
/* No lookup if disabled */
1317-
if (plpgsql_LookupIdentifiers)
1305+
/*
1306+
* We should do nothing in DECLARE sections. In SQL expressions,
1307+
* we really only need to make sure that RECFIELD datums are created
1308+
* when needed.
1309+
*/
1310+
if (plpgsql_IdentifierLookup!=IDENTIFIER_LOOKUP_DECLARE)
13181311
{
13191312
/*
13201313
* Do a lookup in the current namespace stack
@@ -1338,8 +1331,10 @@ plpgsql_parse_dblword(char *word1, char *word2,
13381331
if (nnames==1)
13391332
{
13401333
/*
1341-
* First word is a record name, so second word must be
1342-
* a field in this record.
1334+
* First word is a record name, so second word could
1335+
* be a field in this record. We build a RECFIELD
1336+
* datum whether it is or not --- any error will be
1337+
* detected later.
13431338
*/
13441339
PLpgSQL_recfield*new;
13451340

@@ -1366,8 +1361,9 @@ plpgsql_parse_dblword(char *word1, char *word2,
13661361
if (nnames==1)
13671362
{
13681363
/*
1369-
* First word is a row name, so second word must be a
1370-
* field in this row.
1364+
* First word is a row name, so second word could be
1365+
* a field in this row. Again, no error now if it
1366+
* isn't.
13711367
*/
13721368
PLpgSQL_row*row;
13731369
inti;
@@ -1385,10 +1381,7 @@ plpgsql_parse_dblword(char *word1, char *word2,
13851381
return true;
13861382
}
13871383
}
1388-
ereport(ERROR,
1389-
(errcode(ERRCODE_UNDEFINED_COLUMN),
1390-
errmsg("row \"%s\" has no field \"%s\"",
1391-
word1,word2)));
1384+
/* fall through to return CWORD */
13921385
}
13931386
else
13941387
{
@@ -1399,6 +1392,7 @@ plpgsql_parse_dblword(char *word1, char *word2,
13991392
wdatum->idents=idents;
14001393
return true;
14011394
}
1395+
break;
14021396

14031397
default:
14041398
break;
@@ -1429,8 +1423,12 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
14291423
makeString(word2),
14301424
makeString(word3));
14311425

1432-
/* No lookup if disabled */
1433-
if (plpgsql_LookupIdentifiers)
1426+
/*
1427+
* We should do nothing in DECLARE sections. In SQL expressions,
1428+
* we really only need to make sure that RECFIELD datums are created
1429+
* when needed.
1430+
*/
1431+
if (plpgsql_IdentifierLookup!=IDENTIFIER_LOOKUP_DECLARE)
14341432
{
14351433
/*
14361434
* Do a lookup in the current namespace stack. Must find a qualified
@@ -1446,7 +1444,7 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
14461444
casePLPGSQL_NSTYPE_REC:
14471445
{
14481446
/*
1449-
* words 1/2 are a record name, so third wordmust be a
1447+
* words 1/2 are a record name, so third wordcould be a
14501448
* field in this record.
14511449
*/
14521450
PLpgSQL_recfield*new;
@@ -1468,8 +1466,8 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
14681466
casePLPGSQL_NSTYPE_ROW:
14691467
{
14701468
/*
1471-
* words 1/2 are a row name, so third wordmust be a field
1472-
* in this row.
1469+
* words 1/2 are a row name, so third wordcould be a
1470+
*fieldin this row.
14731471
*/
14741472
PLpgSQL_row*row;
14751473
inti;
@@ -1487,10 +1485,8 @@ plpgsql_parse_tripword(char *word1, char *word2, char *word3,
14871485
return true;
14881486
}
14891487
}
1490-
ereport(ERROR,
1491-
(errcode(ERRCODE_UNDEFINED_COLUMN),
1492-
errmsg("row \"%s.%s\" has no field \"%s\"",
1493-
word1,word2,word3)));
1488+
/* fall through to return CWORD */
1489+
break;
14941490
}
14951491

14961492
default:

‎src/pl/plpgsql/src/pl_scanner.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_scanner.c,v 1.3 2010/01/02 16:58:13 momjian Exp $
12+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_scanner.c,v 1.4 2010/01/10 17:15:18 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -23,8 +23,8 @@
2323
#definePG_KEYWORD(a,b,c) {a,b,c},
2424

2525

26-
/* Klugy flag to tell scannerwhether tolookup identifiers */
27-
boolplpgsql_LookupIdentifiers=true;
26+
/* Klugy flag to tell scannerhow tolook up identifiers */
27+
IdentifierLookupplpgsql_IdentifierLookup=IDENTIFIER_LOOKUP_NORMAL;
2828

2929
/*
3030
* A word about keywords:
@@ -33,11 +33,10 @@ boolplpgsql_LookupIdentifiers = true;
3333
* reserved keywords are passed to the core scanner, so they will be
3434
* recognized before (and instead of) any variable name. Unreserved
3535
* words are checked for separately, after determining that the identifier
36-
* isn't a known variable name. Ifplpgsql_LookupIdentifiers isoff then
36+
* isn't a known variable name. Ifplpgsql_IdentifierLookup isDECLARE then
3737
* no variable names will be recognized, so the unreserved words always work.
3838
* (Note in particular that this helps us avoid reserving keywords that are
39-
* only needed in DECLARE sections, since we scan those sections with
40-
* plpgsql_LookupIdentifiers off.)
39+
* only needed in DECLARE sections.)
4140
*
4241
* In certain contexts it is desirable to prefer recognizing an unreserved
4342
* keyword over recognizing a variable name. Those cases are handled in
@@ -193,7 +192,7 @@ static void location_lineno_init(void);
193192
* It is a wrapper around the core lexer, with the ability to recognize
194193
* PL/pgSQL variables and return them as special T_DATUM tokens. If a
195194
* word or compound word does not match any variable name, or if matching
196-
* is turned off byplpgsql_LookupIdentifiers, it is returned as
195+
* is turned off byplpgsql_IdentifierLookup, it is returned as
197196
* T_WORD or T_CWORD respectively, or as an unreserved keyword if it
198197
* matches one of those.
199198
*/
@@ -567,7 +566,7 @@ plpgsql_scanner_init(const char *str)
567566
scanorig=str;
568567

569568
/* Other setup */
570-
plpgsql_LookupIdentifiers=true;
569+
plpgsql_IdentifierLookup=IDENTIFIER_LOOKUP_NORMAL;
571570

572571
num_pushbacks=0;
573572

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp