Skip to content

Commit 844fe9f

Browse files
committed
Add the ability for the core grammar to have more than one parse target.
This patch essentially allows gram.y to implement a family of related syntax trees, rather than necessarily always parsing a list of SQL statements. raw_parser() gains a new argument, enum RawParseMode, to say what to do. As proof of concept, add a mode that just parses a TypeName without any other decoration, and use that to greatly simplify typeStringToTypeName(). In addition, invent a new SPI entry point SPI_prepare_extended() to allow SPI users (particularly plpgsql) to get at this new functionality. In hopes of making this the last variant of SPI_prepare(), set up its additional arguments as a struct rather than direct arguments, and promise that future additions to the struct can default to zero. SPI_prepare_cursor() and SPI_prepare_params() can perhaps go away at some point. Discussion: https://postgr.es/m/4165684.1607707277@sss.pgh.pa.us
1 parent b49154b commit 844fe9f

File tree

14 files changed

+268
-83
lines changed

14 files changed

+268
-83
lines changed

doc/src/sgml/spi.sgml

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,11 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
11051105
for the <structfield>options</structfield> field of <structname>DeclareCursorStmt</structname>.
11061106
<function>SPI_prepare</function> always takes the cursor options as zero.
11071107
</para>
1108+
1109+
<para>
1110+
This function is now deprecated in favor
1111+
of <function>SPI_prepare_extended</function>.
1112+
</para>
11081113
</refsect1>
11091114

11101115
<refsect1>
@@ -1176,6 +1181,122 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
11761181

11771182
<!-- *********************************************** -->
11781183

1184+
<refentry id="spi-spi-prepare-extended">
1185+
<indexterm><primary>SPI_prepare_extended</primary></indexterm>
1186+
1187+
<refmeta>
1188+
<refentrytitle>SPI_prepare_extended</refentrytitle>
1189+
<manvolnum>3</manvolnum>
1190+
</refmeta>
1191+
1192+
<refnamediv>
1193+
<refname>SPI_prepare_extended</refname>
1194+
<refpurpose>prepare a statement, without executing it yet</refpurpose>
1195+
</refnamediv>
1196+
1197+
<refsynopsisdiv>
1198+
<synopsis>
1199+
SPIPlanPtr SPI_prepare_extended(const char * <parameter>command</parameter>,
1200+
const SPIPrepareOptions * <parameter>options</parameter>)
1201+
</synopsis>
1202+
</refsynopsisdiv>
1203+
1204+
<refsect1>
1205+
<title>Description</title>
1206+
1207+
<para>
1208+
<function>SPI_prepare_extended</function> creates and returns a prepared
1209+
statement for the specified command, but doesn't execute the command.
1210+
This function is equivalent to <function>SPI_prepare</function>,
1211+
with the addition that the caller can specify options to control
1212+
the parsing of external parameter references, as well as other facets
1213+
of query parsing and planning.
1214+
</para>
1215+
</refsect1>
1216+
1217+
<refsect1>
1218+
<title>Arguments</title>
1219+
1220+
<variablelist>
1221+
<varlistentry>
1222+
<term><literal>const char * <parameter>command</parameter></literal></term>
1223+
<listitem>
1224+
<para>
1225+
command string
1226+
</para>
1227+
</listitem>
1228+
</varlistentry>
1229+
1230+
<varlistentry>
1231+
<term><literal>const SPIPrepareOptions * <parameter>options</parameter></literal></term>
1232+
<listitem>
1233+
<para>
1234+
struct containing optional arguments
1235+
</para>
1236+
</listitem>
1237+
</varlistentry>
1238+
</variablelist>
1239+
1240+
<para>
1241+
Callers should always zero out the entire <parameter>options</parameter>
1242+
struct, then fill whichever fields they want to set. This ensures forward
1243+
compatibility of code, since any fields that are added to the struct in
1244+
future will be defined to behave backwards-compatibly if they are zero.
1245+
The currently available <parameter>options</parameter> fields are:
1246+
</para>
1247+
1248+
<variablelist>
1249+
<varlistentry>
1250+
<term><literal>ParserSetupHook <parameter>parserSetup</parameter></literal></term>
1251+
<listitem>
1252+
<para>
1253+
Parser hook setup function
1254+
</para>
1255+
</listitem>
1256+
</varlistentry>
1257+
1258+
<varlistentry>
1259+
<term><literal>void * <parameter>parserSetupArg</parameter></literal></term>
1260+
<listitem>
1261+
<para>
1262+
pass-through argument for <parameter>parserSetup</parameter>
1263+
</para>
1264+
</listitem>
1265+
</varlistentry>
1266+
1267+
<varlistentry>
1268+
<term><literal>RawParseMode <parameter>parseMode</parameter></literal></term>
1269+
<listitem>
1270+
<para>
1271+
mode for raw parsing; <literal>RAW_PARSE_DEFAULT</literal> (zero)
1272+
produces default behavior
1273+
</para>
1274+
</listitem>
1275+
</varlistentry>
1276+
1277+
<varlistentry>
1278+
<term><literal>int <parameter>cursorOptions</parameter></literal></term>
1279+
<listitem>
1280+
<para>
1281+
integer bit mask of cursor options; zero produces default behavior
1282+
</para>
1283+
</listitem>
1284+
</varlistentry>
1285+
</variablelist>
1286+
</refsect1>
1287+
1288+
<refsect1>
1289+
<title>Return Value</title>
1290+
1291+
<para>
1292+
<function>SPI_prepare_extended</function> has the same return conventions as
1293+
<function>SPI_prepare</function>.
1294+
</para>
1295+
</refsect1>
1296+
</refentry>
1297+
1298+
<!-- *********************************************** -->
1299+
11791300
<refentry id="spi-spi-prepare-params">
11801301
<indexterm><primary>SPI_prepare_params</primary></indexterm>
11811302

@@ -1208,6 +1329,11 @@ SPIPlanPtr SPI_prepare_params(const char * <parameter>command</parameter>,
12081329
with the addition that the caller can specify parser hook functions
12091330
to control the parsing of external parameter references.
12101331
</para>
1332+
1333+
<para>
1334+
This function is now deprecated in favor
1335+
of <function>SPI_prepare_extended</function>.
1336+
</para>
12111337
</refsect1>
12121338

12131339
<refsect1>

src/backend/commands/tablecmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12095,7 +12095,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd,
1209512095
* parse_analyze() or the rewriter, but instead we need to pass them
1209612096
* through parse_utilcmd.c to make them ready for execution.
1209712097
*/
12098-
raw_parsetree_list = raw_parser(cmd);
12098+
raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT);
1209912099
querytree_list = NIL;
1210012100
foreach(list_item, raw_parsetree_list)
1210112101
{

src/backend/executor/spi.c

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ SPI_execute(const char *src, bool read_only, long tcount)
508508

509509
memset(&plan, 0, sizeof(_SPI_plan));
510510
plan.magic = _SPI_PLAN_MAGIC;
511+
plan.parse_mode = RAW_PARSE_DEFAULT;
511512
plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
512513

513514
_SPI_prepare_oneshot_plan(src, &plan);
@@ -681,6 +682,7 @@ SPI_execute_with_args(const char *src,
681682

682683
memset(&plan, 0, sizeof(_SPI_plan));
683684
plan.magic = _SPI_PLAN_MAGIC;
685+
plan.parse_mode = RAW_PARSE_DEFAULT;
684686
plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
685687
plan.nargs = nargs;
686688
plan.argtypes = argtypes;
@@ -726,6 +728,7 @@ SPI_execute_with_receiver(const char *src,
726728

727729
memset(&plan, 0, sizeof(_SPI_plan));
728730
plan.magic = _SPI_PLAN_MAGIC;
731+
plan.parse_mode = RAW_PARSE_DEFAULT;
729732
plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
730733
if (params)
731734
{
@@ -768,6 +771,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
768771

769772
memset(&plan, 0, sizeof(_SPI_plan));
770773
plan.magic = _SPI_PLAN_MAGIC;
774+
plan.parse_mode = RAW_PARSE_DEFAULT;
771775
plan.cursor_options = cursorOptions;
772776
plan.nargs = nargs;
773777
plan.argtypes = argtypes;
@@ -784,6 +788,42 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
784788
return result;
785789
}
786790

791+
SPIPlanPtr
792+
SPI_prepare_extended(const char *src,
793+
const SPIPrepareOptions *options)
794+
{
795+
_SPI_plan plan;
796+
SPIPlanPtr result;
797+
798+
if (src == NULL || options == NULL)
799+
{
800+
SPI_result = SPI_ERROR_ARGUMENT;
801+
return NULL;
802+
}
803+
804+
SPI_result = _SPI_begin_call(true);
805+
if (SPI_result < 0)
806+
return NULL;
807+
808+
memset(&plan, 0, sizeof(_SPI_plan));
809+
plan.magic = _SPI_PLAN_MAGIC;
810+
plan.parse_mode = options->parseMode;
811+
plan.cursor_options = options->cursorOptions;
812+
plan.nargs = 0;
813+
plan.argtypes = NULL;
814+
plan.parserSetup = options->parserSetup;
815+
plan.parserSetupArg = options->parserSetupArg;
816+
817+
_SPI_prepare_plan(src, &plan);
818+
819+
/* copy plan to procedure context */
820+
result = _SPI_make_plan_non_temp(&plan);
821+
822+
_SPI_end_call(true);
823+
824+
return result;
825+
}
826+
787827
SPIPlanPtr
788828
SPI_prepare_params(const char *src,
789829
ParserSetupHook parserSetup,
@@ -805,6 +845,7 @@ SPI_prepare_params(const char *src,
805845

806846
memset(&plan, 0, sizeof(_SPI_plan));
807847
plan.magic = _SPI_PLAN_MAGIC;
848+
plan.parse_mode = RAW_PARSE_DEFAULT;
808849
plan.cursor_options = cursorOptions;
809850
plan.nargs = 0;
810851
plan.argtypes = NULL;
@@ -1340,6 +1381,7 @@ SPI_cursor_open_with_args(const char *name,
13401381

13411382
memset(&plan, 0, sizeof(_SPI_plan));
13421383
plan.magic = _SPI_PLAN_MAGIC;
1384+
plan.parse_mode = RAW_PARSE_DEFAULT;
13431385
plan.cursor_options = cursorOptions;
13441386
plan.nargs = nargs;
13451387
plan.argtypes = argtypes;
@@ -1400,6 +1442,7 @@ SPI_cursor_parse_open_with_paramlist(const char *name,
14001442

14011443
memset(&plan, 0, sizeof(_SPI_plan));
14021444
plan.magic = _SPI_PLAN_MAGIC;
1445+
plan.parse_mode = RAW_PARSE_DEFAULT;
14031446
plan.cursor_options = cursorOptions;
14041447
if (params)
14051448
{
@@ -2036,7 +2079,8 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
20362079
* Parse and analyze a querystring.
20372080
*
20382081
* At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup
2039-
* and plan->parserSetupArg) must be valid, as must plan->cursor_options.
2082+
* and plan->parserSetupArg) must be valid, as must plan->parse_mode and
2083+
* plan->cursor_options.
20402084
*
20412085
* Results are stored into *plan (specifically, plan->plancache_list).
20422086
* Note that the result data is all in CurrentMemoryContext or child contexts
@@ -2063,7 +2107,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
20632107
/*
20642108
* Parse the request string into a list of raw parse trees.
20652109
*/
2066-
raw_parsetree_list = pg_parse_query(src);
2110+
raw_parsetree_list = raw_parser(src, plan->parse_mode);
20672111

20682112
/*
20692113
* Do parse analysis and rule rewrite for each raw parsetree, storing the
@@ -2168,7 +2212,7 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
21682212
/*
21692213
* Parse the request string into a list of raw parse trees.
21702214
*/
2171-
raw_parsetree_list = pg_parse_query(src);
2215+
raw_parsetree_list = raw_parser(src, plan->parse_mode);
21722216

21732217
/*
21742218
* Construct plancache entries, but don't do parse analysis yet.
@@ -2866,6 +2910,7 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan)
28662910
newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
28672911
newplan->magic = _SPI_PLAN_MAGIC;
28682912
newplan->plancxt = plancxt;
2913+
newplan->parse_mode = plan->parse_mode;
28692914
newplan->cursor_options = plan->cursor_options;
28702915
newplan->nargs = plan->nargs;
28712916
if (plan->nargs > 0)
@@ -2930,6 +2975,7 @@ _SPI_save_plan(SPIPlanPtr plan)
29302975
newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan));
29312976
newplan->magic = _SPI_PLAN_MAGIC;
29322977
newplan->plancxt = plancxt;
2978+
newplan->parse_mode = plan->parse_mode;
29332979
newplan->cursor_options = plan->cursor_options;
29342980
newplan->nargs = plan->nargs;
29352981
if (plan->nargs > 0)

src/backend/parser/gram.y

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
384384
%type <node> vacuum_relation
385385
%type <selectlimit> opt_select_limit select_limit limit_clause
386386

387-
%type <list> stmtblock stmtmulti
387+
%type <list> parse_toplevel stmtmulti
388388
OptTableElementList TableElementList OptInherit definition
389389
OptTypedTableElementList TypedTableElementList
390390
reloptions opt_reloptions
@@ -723,6 +723,15 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
723723
*/
724724
%token NOT_LA NULLS_LA WITH_LA
725725

726+
/*
727+
* The grammar likewise thinks these tokens are keywords, but they are never
728+
* generated by the scanner. Rather, they can be injected by parser.c as
729+
* the initial token of the string (using the lookahead-token mechanism
730+
* implemented there). This provides a way to tell the grammar to parse
731+
* something other than the usual list of SQL commands.
732+
*/
733+
%token MODE_TYPE_NAME
734+
726735

727736
/* Precedence: lowest to highest */
728737
%nonassoc SET /* see relation_expr_opt_alias */
@@ -787,11 +796,20 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
787796

788797
/*
789798
* The target production for the whole parse.
799+
*
800+
* Ordinarily we parse a list of statements, but if we see one of the
801+
* special MODE_XXX symbols as first token, we parse something else.
802+
* The options here correspond to enum RawParseMode, which see for details.
790803
*/
791-
stmtblock: stmtmulti
804+
parse_toplevel:
805+
stmtmulti
792806
{
793807
pg_yyget_extra(yyscanner)->parsetree = $1;
794808
}
809+
| MODE_TYPE_NAME Typename
810+
{
811+
pg_yyget_extra(yyscanner)->parsetree = list_make1($2);
812+
}
795813
;
796814

797815
/*

src/backend/parser/parse_coerce.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,7 +1541,7 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type)
15411541

15421542
foreach(lc, exprs)
15431543
{
1544-
Node *expr = (Node *) lfirst(lc);
1544+
Node *expr = (Node *) lfirst(lc);
15451545

15461546
/* Types must match */
15471547
if (exprType(expr) != common_type)
@@ -2380,7 +2380,8 @@ enforce_generic_type_consistency(const Oid *actual_arg_types,
23802380
if (!OidIsValid(elem_typeid))
23812381
{
23822382
/*
2383-
* if we don't have an element type yet, use the one we just got
2383+
* if we don't have an element type yet, use the one we just
2384+
* got
23842385
*/
23852386
elem_typeid = range_typelem;
23862387
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy