diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-04 11:03:22 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-04 11:03:22 -0500 |
commit | 844fe9f159a948377907a63d0ef3fb16dc51ce50 (patch) | |
tree | 5f2ac3f159f7a4795a01330044fd76049ed5bff6 | |
parent | b49154b3b7a45523ce4081fdae8d65049342fcec (diff) | |
download | postgresql-844fe9f159a948377907a63d0ef3fb16dc51ce50.tar.gz postgresql-844fe9f159a948377907a63d0ef3fb16dc51ce50.zip |
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
-rw-r--r-- | doc/src/sgml/spi.sgml | 126 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 2 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 52 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 22 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 5 | ||||
-rw-r--r-- | src/backend/parser/parse_type.c | 64 | ||||
-rw-r--r-- | src/backend/parser/parser.c | 27 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 2 | ||||
-rw-r--r-- | src/include/executor/spi.h | 13 | ||||
-rw-r--r-- | src/include/executor/spi_priv.h | 1 | ||||
-rw-r--r-- | src/include/parser/parser.h | 20 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/parse.pl | 2 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 13 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_gram.y | 2 |
14 files changed, 268 insertions, 83 deletions
diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 6e92e15ca3b..f5e0a35da06 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1105,6 +1105,11 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int < for the <structfield>options</structfield> field of <structname>DeclareCursorStmt</structname>. <function>SPI_prepare</function> always takes the cursor options as zero. </para> + + <para> + This function is now deprecated in favor + of <function>SPI_prepare_extended</function>. + </para> </refsect1> <refsect1> @@ -1176,6 +1181,122 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int < <!-- *********************************************** --> +<refentry id="spi-spi-prepare-extended"> + <indexterm><primary>SPI_prepare_extended</primary></indexterm> + + <refmeta> + <refentrytitle>SPI_prepare_extended</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>SPI_prepare_extended</refname> + <refpurpose>prepare a statement, without executing it yet</refpurpose> + </refnamediv> + + <refsynopsisdiv> +<synopsis> +SPIPlanPtr SPI_prepare_extended(const char * <parameter>command</parameter>, + const SPIPrepareOptions * <parameter>options</parameter>) +</synopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para> + <function>SPI_prepare_extended</function> creates and returns a prepared + statement for the specified command, but doesn't execute the command. + This function is equivalent to <function>SPI_prepare</function>, + with the addition that the caller can specify options to control + the parsing of external parameter references, as well as other facets + of query parsing and planning. + </para> + </refsect1> + + <refsect1> + <title>Arguments</title> + + <variablelist> + <varlistentry> + <term><literal>const char * <parameter>command</parameter></literal></term> + <listitem> + <para> + command string + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>const SPIPrepareOptions * <parameter>options</parameter></literal></term> + <listitem> + <para> + struct containing optional arguments + </para> + </listitem> + </varlistentry> + </variablelist> + + <para> + Callers should always zero out the entire <parameter>options</parameter> + struct, then fill whichever fields they want to set. This ensures forward + compatibility of code, since any fields that are added to the struct in + future will be defined to behave backwards-compatibly if they are zero. + The currently available <parameter>options</parameter> fields are: + </para> + + <variablelist> + <varlistentry> + <term><literal>ParserSetupHook <parameter>parserSetup</parameter></literal></term> + <listitem> + <para> + Parser hook setup function + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>void * <parameter>parserSetupArg</parameter></literal></term> + <listitem> + <para> + pass-through argument for <parameter>parserSetup</parameter> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>RawParseMode <parameter>parseMode</parameter></literal></term> + <listitem> + <para> + mode for raw parsing; <literal>RAW_PARSE_DEFAULT</literal> (zero) + produces default behavior + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>int <parameter>cursorOptions</parameter></literal></term> + <listitem> + <para> + integer bit mask of cursor options; zero produces default behavior + </para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para> + <function>SPI_prepare_extended</function> has the same return conventions as + <function>SPI_prepare</function>. + </para> + </refsect1> +</refentry> + +<!-- *********************************************** --> + <refentry id="spi-spi-prepare-params"> <indexterm><primary>SPI_prepare_params</primary></indexterm> @@ -1208,6 +1329,11 @@ SPIPlanPtr SPI_prepare_params(const char * <parameter>command</parameter>, with the addition that the caller can specify parser hook functions to control the parsing of external parameter references. </para> + + <para> + This function is now deprecated in favor + of <function>SPI_prepare_extended</function>. + </para> </refsect1> <refsect1> diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 11dae782fd2..993da56d437 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -12095,7 +12095,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, * parse_analyze() or the rewriter, but instead we need to pass them * through parse_utilcmd.c to make them ready for execution. */ - raw_parsetree_list = raw_parser(cmd); + raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT); querytree_list = NIL; foreach(list_item, raw_parsetree_list) { diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 8368ead1ef6..6c0593686a9 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -508,6 +508,7 @@ SPI_execute(const char *src, bool read_only, long tcount) memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; _SPI_prepare_oneshot_plan(src, &plan); @@ -681,6 +682,7 @@ SPI_execute_with_args(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; plan.nargs = nargs; plan.argtypes = argtypes; @@ -726,6 +728,7 @@ SPI_execute_with_receiver(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; if (params) { @@ -768,6 +771,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; @@ -785,6 +789,42 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, } SPIPlanPtr +SPI_prepare_extended(const char *src, + const SPIPrepareOptions *options) +{ + _SPI_plan plan; + SPIPlanPtr result; + + if (src == NULL || options == NULL) + { + SPI_result = SPI_ERROR_ARGUMENT; + return NULL; + } + + SPI_result = _SPI_begin_call(true); + if (SPI_result < 0) + return NULL; + + memset(&plan, 0, sizeof(_SPI_plan)); + plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = options->parseMode; + plan.cursor_options = options->cursorOptions; + plan.nargs = 0; + plan.argtypes = NULL; + plan.parserSetup = options->parserSetup; + plan.parserSetupArg = options->parserSetupArg; + + _SPI_prepare_plan(src, &plan); + + /* copy plan to procedure context */ + result = _SPI_make_plan_non_temp(&plan); + + _SPI_end_call(true); + + return result; +} + +SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, @@ -805,6 +845,7 @@ SPI_prepare_params(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = 0; plan.argtypes = NULL; @@ -1340,6 +1381,7 @@ SPI_cursor_open_with_args(const char *name, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; @@ -1400,6 +1442,7 @@ SPI_cursor_parse_open_with_paramlist(const char *name, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; if (params) { @@ -2036,7 +2079,8 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) * Parse and analyze a querystring. * * At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup - * and plan->parserSetupArg) must be valid, as must plan->cursor_options. + * and plan->parserSetupArg) must be valid, as must plan->parse_mode and + * plan->cursor_options. * * Results are stored into *plan (specifically, plan->plancache_list). * Note that the result data is all in CurrentMemoryContext or child contexts @@ -2063,7 +2107,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src); + raw_parsetree_list = raw_parser(src, plan->parse_mode); /* * 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) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src); + raw_parsetree_list = raw_parser(src, plan->parse_mode); /* * Construct plancache entries, but don't do parse analysis yet. @@ -2866,6 +2910,7 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan) newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->plancxt = plancxt; + newplan->parse_mode = plan->parse_mode; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) @@ -2930,6 +2975,7 @@ _SPI_save_plan(SPIPlanPtr plan) newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->plancxt = plancxt; + newplan->parse_mode = plan->parse_mode; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 18e181d5005..fb025f08a4e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -384,7 +384,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> vacuum_relation %type <selectlimit> opt_select_limit select_limit limit_clause -%type <list> stmtblock stmtmulti +%type <list> parse_toplevel stmtmulti OptTableElementList TableElementList OptInherit definition OptTypedTableElementList TypedTableElementList reloptions opt_reloptions @@ -723,6 +723,15 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); */ %token NOT_LA NULLS_LA WITH_LA +/* + * The grammar likewise thinks these tokens are keywords, but they are never + * generated by the scanner. Rather, they can be injected by parser.c as + * the initial token of the string (using the lookahead-token mechanism + * implemented there). This provides a way to tell the grammar to parse + * something other than the usual list of SQL commands. + */ +%token MODE_TYPE_NAME + /* Precedence: lowest to highest */ %nonassoc SET /* see relation_expr_opt_alias */ @@ -787,11 +796,20 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); /* * The target production for the whole parse. + * + * Ordinarily we parse a list of statements, but if we see one of the + * special MODE_XXX symbols as first token, we parse something else. + * The options here correspond to enum RawParseMode, which see for details. */ -stmtblock: stmtmulti +parse_toplevel: + stmtmulti { pg_yyget_extra(yyscanner)->parsetree = $1; } + | MODE_TYPE_NAME Typename + { + pg_yyget_extra(yyscanner)->parsetree = list_make1($2); + } ; /* diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 8d01fca6d21..74eb39c0e4d 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -1541,7 +1541,7 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type) foreach(lc, exprs) { - Node *expr = (Node *) lfirst(lc); + Node *expr = (Node *) lfirst(lc); /* Types must match */ if (exprType(expr) != common_type) @@ -2380,7 +2380,8 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, if (!OidIsValid(elem_typeid)) { /* - * if we don't have an element type yet, use the one we just got + * if we don't have an element type yet, use the one we just + * got */ elem_typeid = range_typelem; } diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 717125ad873..abe131ebebf 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -719,13 +719,6 @@ pts_error_callback(void *arg) const char *str = (const char *) arg; errcontext("invalid type name \"%s\"", str); - - /* - * Currently we just suppress any syntax error position report, rather - * than transforming to an "internal query" error. It's unlikely that a - * type name is complex enough to need positioning. - */ - errposition(0); } /* @@ -737,11 +730,7 @@ pts_error_callback(void *arg) TypeName * typeStringToTypeName(const char *str) { - StringInfoData buf; List *raw_parsetree_list; - SelectStmt *stmt; - ResTarget *restarget; - TypeCast *typecast; TypeName *typeName; ErrorContextCallback ptserrcontext; @@ -749,9 +738,6 @@ typeStringToTypeName(const char *str) if (strspn(str, " \t\n\r\f") == strlen(str)) goto fail; - initStringInfo(&buf); - appendStringInfo(&buf, "SELECT NULL::%s", str); - /* * Setup error traceback support in case of ereport() during parse */ @@ -760,58 +746,18 @@ typeStringToTypeName(const char *str) ptserrcontext.previous = error_context_stack; error_context_stack = &ptserrcontext; - raw_parsetree_list = raw_parser(buf.data); + raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME); error_context_stack = ptserrcontext.previous; - /* - * Make sure we got back exactly what we expected and no more; paranoia is - * justified since the string might contain anything. - */ - if (list_length(raw_parsetree_list) != 1) - goto fail; - stmt = (SelectStmt *) linitial_node(RawStmt, raw_parsetree_list)->stmt; - if (stmt == NULL || - !IsA(stmt, SelectStmt) || - stmt->distinctClause != NIL || - stmt->intoClause != NULL || - stmt->fromClause != NIL || - stmt->whereClause != NULL || - stmt->groupClause != NIL || - stmt->havingClause != NULL || - stmt->windowClause != NIL || - stmt->valuesLists != NIL || - stmt->sortClause != NIL || - stmt->limitOffset != NULL || - stmt->limitCount != NULL || - stmt->lockingClause != NIL || - stmt->withClause != NULL || - stmt->op != SETOP_NONE) - goto fail; - if (list_length(stmt->targetList) != 1) - goto fail; - restarget = (ResTarget *) linitial(stmt->targetList); - if (restarget == NULL || - !IsA(restarget, ResTarget) || - restarget->name != NULL || - restarget->indirection != NIL) - goto fail; - typecast = (TypeCast *) restarget->val; - if (typecast == NULL || - !IsA(typecast, TypeCast) || - typecast->arg == NULL || - !IsA(typecast->arg, A_Const)) - goto fail; + /* We should get back exactly one TypeName node. */ + Assert(list_length(raw_parsetree_list) == 1); + typeName = linitial_node(TypeName, raw_parsetree_list); - typeName = typecast->typeName; - if (typeName == NULL || - !IsA(typeName, TypeName)) - goto fail; + /* The grammar allows SETOF in TypeName, but we don't want that here. */ if (typeName->setof) goto fail; - pfree(buf.data); - return typeName; fail: diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index b897a5160a2..8eb8feb372e 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -35,11 +35,11 @@ static char *str_udeescape(const char *str, char escape, * raw_parser * Given a query in string form, do lexical and grammatical analysis. * - * Returns a list of raw (un-analyzed) parse trees. The immediate elements - * of the list are always RawStmt nodes. + * Returns a list of raw (un-analyzed) parse trees. The contents of the + * list have the form required by the specified RawParseMode. */ List * -raw_parser(const char *str) +raw_parser(const char *str, RawParseMode mode) { core_yyscan_t yyscanner; base_yy_extra_type yyextra; @@ -49,8 +49,22 @@ raw_parser(const char *str) yyscanner = scanner_init(str, &yyextra.core_yy_extra, &ScanKeywords, ScanKeywordTokens); - /* base_yylex() only needs this much initialization */ - yyextra.have_lookahead = false; + /* base_yylex() only needs us to initialize the lookahead token, if any */ + if (mode == RAW_PARSE_DEFAULT) + yyextra.have_lookahead = false; + else + { + /* this array is indexed by RawParseMode enum */ + static const int mode_token[] = { + 0, /* RAW_PARSE_DEFAULT */ + MODE_TYPE_NAME /* RAW_PARSE_TYPE_NAME */ + }; + + yyextra.have_lookahead = true; + yyextra.lookahead_token = mode_token[mode]; + yyextra.lookahead_yylloc = 0; + yyextra.lookahead_end = NULL; + } /* initialize the bison parser */ parser_init(&yyextra); @@ -104,7 +118,8 @@ base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) cur_token = yyextra->lookahead_token; lvalp->core_yystype = yyextra->lookahead_yylval; *llocp = yyextra->lookahead_yylloc; - *(yyextra->lookahead_end) = yyextra->lookahead_hold_char; + if (yyextra->lookahead_end) + *(yyextra->lookahead_end) = yyextra->lookahead_hold_char; yyextra->have_lookahead = false; } else diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index dfa0d685a83..f5c14249d13 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -635,7 +635,7 @@ pg_parse_query(const char *query_string) if (log_parser_stats) ResetUsage(); - raw_parsetree_list = raw_parser(query_string); + raw_parsetree_list = raw_parser(query_string, RAW_PARSE_DEFAULT); if (log_parser_stats) ShowUsage("PARSER STATISTICS"); diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 6e603d007d7..9c70603434a 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -15,7 +15,7 @@ #include "commands/trigger.h" #include "lib/ilist.h" -#include "nodes/parsenodes.h" +#include "parser/parser.h" #include "utils/portal.h" @@ -33,6 +33,15 @@ typedef struct SPITupleTable SubTransactionId subid; /* subxact in which tuptable was created */ } SPITupleTable; +/* Optional arguments for SPI_prepare_extended */ +typedef struct SPIPrepareOptions +{ + ParserSetupHook parserSetup; + void *parserSetupArg; + RawParseMode parseMode; + int cursorOptions; +} SPIPrepareOptions; + /* Plans are opaque structs for standard users of SPI */ typedef struct _SPI_plan *SPIPlanPtr; @@ -113,6 +122,8 @@ extern int SPI_execute_with_receiver(const char *src, extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes); extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cursorOptions); +extern SPIPlanPtr SPI_prepare_extended(const char *src, + const SPIPrepareOptions *options); extern SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h index 29a77781a9d..ce0f58ce687 100644 --- a/src/include/executor/spi_priv.h +++ b/src/include/executor/spi_priv.h @@ -95,6 +95,7 @@ typedef struct _SPI_plan bool no_snapshots; /* let the caller handle the snapshots */ List *plancache_list; /* one CachedPlanSource per parsetree */ MemoryContext plancxt; /* Context containing _SPI_plan and data */ + RawParseMode parse_mode; /* raw_parser() mode */ int cursor_options; /* Cursor options used for planning */ int nargs; /* number of plan arguments */ Oid *argtypes; /* Argument types (NULL if nargs is 0) */ diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 09730030444..80d90027cc4 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -18,6 +18,24 @@ #include "nodes/parsenodes.h" +/* + * RawParseMode determines the form of the string that raw_parser() accepts: + * + * RAW_PARSE_DEFAULT: parse a semicolon-separated list of SQL commands, + * and return a List of RawStmt nodes. + * + * RAW_PARSE_TYPE_NAME: parse a type name, and return a one-element List + * containing a TypeName node. + * + * ... more to come ... + */ +typedef enum +{ + RAW_PARSE_DEFAULT = 0, + RAW_PARSE_TYPE_NAME +} RawParseMode; + +/* Values for the backslash_quote GUC */ typedef enum { BACKSLASH_QUOTE_OFF, @@ -32,7 +50,7 @@ extern PGDLLIMPORT bool standard_conforming_strings; /* Primary entry point for the raw parsing functions */ -extern List *raw_parser(const char *str); +extern List *raw_parser(const char *str, RawParseMode mode); /* Utility functions exported by gram.y (perhaps these should be elsewhere) */ extern List *SystemFuncName(char *name); diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index f2731ea873a..7f9be85eb66 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -63,7 +63,7 @@ my %replace_types = ( 'opt_array_bounds' => '<index>', # "ignore" means: do not create type and rules for this non-term-id - 'stmtblock' => 'ignore', + 'parse_toplevel' => 'ignore', 'stmtmulti' => 'ignore', 'CreateAsStmt' => 'ignore', 'DeallocateStmt' => 'ignore', diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index f966ddf0b5e..4a51fb6d9f1 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -4168,6 +4168,7 @@ exec_prepare_plan(PLpgSQL_execstate *estate, bool keepplan) { SPIPlanPtr plan; + SPIPrepareOptions options; /* * The grammar can't conveniently set expr->func while building the parse @@ -4178,12 +4179,14 @@ exec_prepare_plan(PLpgSQL_execstate *estate, /* * Generate and save the plan */ - plan = SPI_prepare_params(expr->query, - (ParserSetupHook) plpgsql_parser_setup, - (void *) expr, - cursorOptions); + memset(&options, 0, sizeof(options)); + options.parserSetup = (ParserSetupHook) plpgsql_parser_setup; + options.parserSetupArg = (void *) expr; + options.parseMode = RAW_PARSE_DEFAULT; + options.cursorOptions = cursorOptions; + plan = SPI_prepare_extended(expr->query, &options); if (plan == NULL) - elog(ERROR, "SPI_prepare_params failed for \"%s\": %s", + elog(ERROR, "SPI_prepare_extended failed for \"%s\": %s", expr->query, SPI_result_code_string(SPI_result)); if (keepplan) SPI_keepplan(plan); diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index a154b9841a6..c09576efff5 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -3661,7 +3661,7 @@ check_sql_expr(const char *stmt, int location, int leaderlen) error_context_stack = &syntax_errcontext; oldCxt = MemoryContextSwitchTo(plpgsql_compile_tmp_cxt); - (void) raw_parser(stmt); + (void) raw_parser(stmt, RAW_PARSE_DEFAULT); MemoryContextSwitchTo(oldCxt); /* Restore former ereport callback */ |