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

Commitc9d5298

Browse files
committed
Re-implement pl/pgsql's expression and assignment parsing.
Invent new RawParseModes that allow the core grammar to handlepl/pgsql expressions and assignments directly, and thereby get ridof a lot of hackery in pl/pgsql's parser. This moves a good dealof knowledge about pl/pgsql into the core code: notably, we have toinvent a CoercionContext that matches pl/pgsql's (rather dubious)historical behavior for assignment coercions. That's getting awayfrom the original idea of pl/pgsql as an arm's-length extension ofthe core, but really we crossed that bridge a long time ago.The main advantage of doing this is that we can now use the coreparser to generate FieldStore and/or SubscriptingRef nodes to handleassignments to pl/pgsql variables that are records or arrays. Thatfixes a number of cases that had never been implemented in pl/pgsqlassignment, such as nested records and array slicing, and it allowspl/pgsql assignment to support the datatype-specific subscriptingbehaviors introduced in commitc7aba7c.There are cosmetic benefits too: when a syntax error occurs in apl/pgsql expression, the error report no longer includes the confusing"SELECT" keyword that used to get prefixed to the expression text.Also, there seem to be some small speed gains.Discussion:https://postgr.es/m/4165684.1607707277@sss.pgh.pa.us
1 parent844fe9f commitc9d5298

32 files changed

+1081
-159
lines changed

‎contrib/hstore/expected/hstore.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,6 +1583,10 @@ select f2 from test_json_agg;
15831583
"d"=>NULL, "x"=>"xyzzy"
15841584
(3 rows)
15851585

1586+
-- Test subscripting in plpgsql
1587+
do $$ declare h hstore;
1588+
begin h['a'] := 'b'; raise notice 'h = %, h[a] = %', h, h['a']; end $$;
1589+
NOTICE: h = "a"=>"b", h[a] = b
15861590
-- Check the hstore_hash() and hstore_hash_extended() function explicitly.
15871591
SELECT v as value, hstore_hash(v)::bit(32) as standard,
15881592
hstore_hash_extended(v, 0)::bit(32) as extended0,

‎contrib/hstore/sql/hstore.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,10 @@ select f2['d':'e'] from test_json_agg; -- error
372372
update test_json_aggset f2['d']= f2['e'], f2['x']='xyzzy';
373373
select f2from test_json_agg;
374374

375+
-- Test subscripting in plpgsql
376+
do $$ declare h hstore;
377+
begin h['a'] :='b'; raise notice'h = %, h[a] = %', h, h['a']; end $$;
378+
375379
-- Check the hstore_hash() and hstore_hash_extended() function explicitly.
376380
SELECT vas value, hstore_hash(v)::bit(32)as standard,
377381
hstore_hash_extended(v,0)::bit(32)as extended0,

‎doc/src/sgml/plpgsql.sgml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -946,8 +946,8 @@ PREPARE <replaceable>statement_name</replaceable>(integer, integer) AS SELECT $1
946946
database engine. The expression must yield a single value (possibly
947947
a row value, if the variable is a row or record variable). The target
948948
variable can be a simple variable (optionally qualified with a block
949-
name), a field of a row or recordvariable, or an elementof an array
950-
that is a simple variable or field. Equal (<literal>=</literal>) can be
949+
name), a field of a row or recordtarget, or an elementor slice of
950+
an array target. Equal (<literal>=</literal>) can be
951951
used instead of PL/SQL-compliant <literal>:=</literal>.
952952
</para>
953953

@@ -968,8 +968,25 @@ PREPARE <replaceable>statement_name</replaceable>(integer, integer) AS SELECT $1
968968
<programlisting>
969969
tax := subtotal * 0.06;
970970
my_record.user_id := 20;
971+
my_array[j] := 20;
972+
my_array[1:3] := array[1,2,3];
973+
complex_array[n].realpart = 12.3;
971974
</programlisting>
972975
</para>
976+
977+
<para>
978+
It's useful to know that what follows the assignment operator is
979+
essentially treated as a <literal>SELECT</literal> command; as long
980+
as it returns a single row and column, it will work. Thus for example
981+
one can write something like
982+
<programlisting>
983+
total_sales := sum(quantity) from sales;
984+
</programlisting>
985+
This provides an effect similar to the single-row <literal>SELECT
986+
... INTO</literal> syntax described in
987+
<xref linkend="plpgsql-statements-sql-onerow"/>. However, that syntax
988+
is more portable.
989+
</para>
973990
</sect2>
974991

975992
<sect2 id="plpgsql-statements-sql-noresult">

‎src/backend/commands/functioncmds.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,7 @@ CreateCast(CreateCastStmt *stmt)
16281628
caseCOERCION_ASSIGNMENT:
16291629
castcontext=COERCION_CODE_ASSIGNMENT;
16301630
break;
1631+
/* COERCION_PLPGSQL is intentionally not covered here */
16311632
caseCOERCION_EXPLICIT:
16321633
castcontext=COERCION_CODE_EXPLICIT;
16331634
break;

‎src/backend/executor/spi.c

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ static _SPI_connection *_SPI_current = NULL;
5151
staticint_SPI_stack_depth=0;/* allocated size of _SPI_stack */
5252
staticint_SPI_connected=-1;/* current stack index */
5353

54+
typedefstructSPICallbackArg
55+
{
56+
constchar*query;
57+
RawParseModemode;
58+
}SPICallbackArg;
59+
5460
staticPortalSPI_cursor_open_internal(constchar*name,SPIPlanPtrplan,
5561
ParamListInfoparamLI,boolread_only);
5662

@@ -1479,6 +1485,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
14791485
Snapshotsnapshot;
14801486
MemoryContextoldcontext;
14811487
Portalportal;
1488+
SPICallbackArgspicallbackarg;
14821489
ErrorContextCallbackspierrcontext;
14831490

14841491
/*
@@ -1533,8 +1540,10 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
15331540
* Setup error traceback support for ereport(), in case GetCachedPlan
15341541
* throws an error.
15351542
*/
1543+
spicallbackarg.query=plansource->query_string;
1544+
spicallbackarg.mode=plan->parse_mode;
15361545
spierrcontext.callback=_SPI_error_callback;
1537-
spierrcontext.arg=unconstify(char*,plansource->query_string);
1546+
spierrcontext.arg=&spicallbackarg;
15381547
spierrcontext.previous=error_context_stack;
15391548
error_context_stack=&spierrcontext;
15401549

@@ -1952,6 +1961,7 @@ SPI_plan_get_cached_plan(SPIPlanPtr plan)
19521961
{
19531962
CachedPlanSource*plansource;
19541963
CachedPlan*cplan;
1964+
SPICallbackArgspicallbackarg;
19551965
ErrorContextCallbackspierrcontext;
19561966

19571967
Assert(plan->magic==_SPI_PLAN_MAGIC);
@@ -1966,8 +1976,10 @@ SPI_plan_get_cached_plan(SPIPlanPtr plan)
19661976
plansource= (CachedPlanSource*)linitial(plan->plancache_list);
19671977

19681978
/* Setup error traceback support for ereport() */
1979+
spicallbackarg.query=plansource->query_string;
1980+
spicallbackarg.mode=plan->parse_mode;
19691981
spierrcontext.callback=_SPI_error_callback;
1970-
spierrcontext.arg=unconstify(char*,plansource->query_string);
1982+
spierrcontext.arg=&spicallbackarg;
19711983
spierrcontext.previous=error_context_stack;
19721984
error_context_stack=&spierrcontext;
19731985

@@ -2094,13 +2106,16 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
20942106
List*raw_parsetree_list;
20952107
List*plancache_list;
20962108
ListCell*list_item;
2109+
SPICallbackArgspicallbackarg;
20972110
ErrorContextCallbackspierrcontext;
20982111

20992112
/*
21002113
* Setup error traceback support for ereport()
21012114
*/
2115+
spicallbackarg.query=src;
2116+
spicallbackarg.mode=plan->parse_mode;
21022117
spierrcontext.callback=_SPI_error_callback;
2103-
spierrcontext.arg=unconstify(char*,src);
2118+
spierrcontext.arg=&spicallbackarg;
21042119
spierrcontext.previous=error_context_stack;
21052120
error_context_stack=&spierrcontext;
21062121

@@ -2199,13 +2214,16 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
21992214
List*raw_parsetree_list;
22002215
List*plancache_list;
22012216
ListCell*list_item;
2217+
SPICallbackArgspicallbackarg;
22022218
ErrorContextCallbackspierrcontext;
22032219

22042220
/*
22052221
* Setup error traceback support for ereport()
22062222
*/
2223+
spicallbackarg.query=src;
2224+
spicallbackarg.mode=plan->parse_mode;
22072225
spierrcontext.callback=_SPI_error_callback;
2208-
spierrcontext.arg=unconstify(char*,src);
2226+
spierrcontext.arg=&spicallbackarg;
22092227
spierrcontext.previous=error_context_stack;
22102228
error_context_stack=&spierrcontext;
22112229

@@ -2263,15 +2281,18 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
22632281
SPITupleTable*my_tuptable=NULL;
22642282
intres=0;
22652283
boolpushed_active_snap= false;
2284+
SPICallbackArgspicallbackarg;
22662285
ErrorContextCallbackspierrcontext;
22672286
CachedPlan*cplan=NULL;
22682287
ListCell*lc1;
22692288

22702289
/*
22712290
* Setup error traceback support for ereport()
22722291
*/
2292+
spicallbackarg.query=NULL;/* we'll fill this below */
2293+
spicallbackarg.mode=plan->parse_mode;
22732294
spierrcontext.callback=_SPI_error_callback;
2274-
spierrcontext.arg=NULL;/* we'll fill this below */
2295+
spierrcontext.arg=&spicallbackarg;
22752296
spierrcontext.previous=error_context_stack;
22762297
error_context_stack=&spierrcontext;
22772298

@@ -2318,7 +2339,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
23182339
List*stmt_list;
23192340
ListCell*lc2;
23202341

2321-
spierrcontext.arg=unconstify(char*,plansource->query_string);
2342+
spicallbackarg.query=plansource->query_string;
23222343

23232344
/*
23242345
* If this is a one-shot plan, we still need to do parse analysis.
@@ -2722,7 +2743,8 @@ _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
27222743
staticvoid
27232744
_SPI_error_callback(void*arg)
27242745
{
2725-
constchar*query= (constchar*)arg;
2746+
SPICallbackArg*carg= (SPICallbackArg*)arg;
2747+
constchar*query=carg->query;
27262748
intsyntaxerrposition;
27272749

27282750
if (query==NULL)/* in case arg wasn't set yet */
@@ -2740,7 +2762,23 @@ _SPI_error_callback(void *arg)
27402762
internalerrquery(query);
27412763
}
27422764
else
2743-
errcontext("SQL statement \"%s\"",query);
2765+
{
2766+
/* Use the parse mode to decide how to describe the query */
2767+
switch (carg->mode)
2768+
{
2769+
caseRAW_PARSE_PLPGSQL_EXPR:
2770+
errcontext("SQL expression \"%s\"",query);
2771+
break;
2772+
caseRAW_PARSE_PLPGSQL_ASSIGN1:
2773+
caseRAW_PARSE_PLPGSQL_ASSIGN2:
2774+
caseRAW_PARSE_PLPGSQL_ASSIGN3:
2775+
errcontext("PL/pgSQL assignment \"%s\"",query);
2776+
break;
2777+
default:
2778+
errcontext("SQL statement \"%s\"",query);
2779+
break;
2780+
}
2781+
}
27442782
}
27452783

27462784
/*

‎src/backend/nodes/copyfuncs.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,6 +3199,20 @@ _copySetOperationStmt(const SetOperationStmt *from)
31993199
returnnewnode;
32003200
}
32013201

3202+
staticPLAssignStmt*
3203+
_copyPLAssignStmt(constPLAssignStmt*from)
3204+
{
3205+
PLAssignStmt*newnode=makeNode(PLAssignStmt);
3206+
3207+
COPY_STRING_FIELD(name);
3208+
COPY_NODE_FIELD(indirection);
3209+
COPY_SCALAR_FIELD(nnames);
3210+
COPY_NODE_FIELD(val);
3211+
COPY_LOCATION_FIELD(location);
3212+
3213+
returnnewnode;
3214+
}
3215+
32023216
staticAlterTableStmt*
32033217
_copyAlterTableStmt(constAlterTableStmt*from)
32043218
{
@@ -5220,6 +5234,9 @@ copyObjectImpl(const void *from)
52205234
caseT_SetOperationStmt:
52215235
retval=_copySetOperationStmt(from);
52225236
break;
5237+
caseT_PLAssignStmt:
5238+
retval=_copyPLAssignStmt(from);
5239+
break;
52235240
caseT_AlterTableStmt:
52245241
retval=_copyAlterTableStmt(from);
52255242
break;

‎src/backend/nodes/equalfuncs.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,18 @@ _equalSetOperationStmt(const SetOperationStmt *a, const SetOperationStmt *b)
10851085
return true;
10861086
}
10871087

1088+
staticbool
1089+
_equalPLAssignStmt(constPLAssignStmt*a,constPLAssignStmt*b)
1090+
{
1091+
COMPARE_STRING_FIELD(name);
1092+
COMPARE_NODE_FIELD(indirection);
1093+
COMPARE_SCALAR_FIELD(nnames);
1094+
COMPARE_NODE_FIELD(val);
1095+
COMPARE_LOCATION_FIELD(location);
1096+
1097+
return true;
1098+
}
1099+
10881100
staticbool
10891101
_equalAlterTableStmt(constAlterTableStmt*a,constAlterTableStmt*b)
10901102
{
@@ -3275,6 +3287,9 @@ equal(const void *a, const void *b)
32753287
caseT_SetOperationStmt:
32763288
retval=_equalSetOperationStmt(a,b);
32773289
break;
3290+
caseT_PLAssignStmt:
3291+
retval=_equalPLAssignStmt(a,b);
3292+
break;
32783293
caseT_AlterTableStmt:
32793294
retval=_equalAlterTableStmt(a,b);
32803295
break;

‎src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,6 +3669,16 @@ raw_expression_tree_walker(Node *node,
36693669
return true;
36703670
}
36713671
break;
3672+
caseT_PLAssignStmt:
3673+
{
3674+
PLAssignStmt*stmt= (PLAssignStmt*)node;
3675+
3676+
if (walker(stmt->indirection,context))
3677+
return true;
3678+
if (walker(stmt->val,context))
3679+
return true;
3680+
}
3681+
break;
36723682
caseT_A_Expr:
36733683
{
36743684
A_Expr*expr= (A_Expr*)node;

‎src/backend/nodes/outfuncs.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,6 +2775,18 @@ _outSelectStmt(StringInfo str, const SelectStmt *node)
27752775
WRITE_NODE_FIELD(rarg);
27762776
}
27772777

2778+
staticvoid
2779+
_outPLAssignStmt(StringInfostr,constPLAssignStmt*node)
2780+
{
2781+
WRITE_NODE_TYPE("PLASSIGN");
2782+
2783+
WRITE_STRING_FIELD(name);
2784+
WRITE_NODE_FIELD(indirection);
2785+
WRITE_INT_FIELD(nnames);
2786+
WRITE_NODE_FIELD(val);
2787+
WRITE_LOCATION_FIELD(location);
2788+
}
2789+
27782790
staticvoid
27792791
_outFuncCall(StringInfostr,constFuncCall*node)
27802792
{
@@ -4211,6 +4223,9 @@ outNode(StringInfo str, const void *obj)
42114223
caseT_SelectStmt:
42124224
_outSelectStmt(str,obj);
42134225
break;
4226+
caseT_PLAssignStmt:
4227+
_outPLAssignStmt(str,obj);
4228+
break;
42144229
caseT_ColumnDef:
42154230
_outColumnDef(str,obj);
42164231
break;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp