Add the ability for the core grammar to have more than one parse target.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 4 Jan 2021 16:03:22 +0000 (11:03 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 4 Jan 2021 16:03:22 +0000 (11:03 -0500)
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

14 files changed:
doc/src/sgml/spi.sgml
src/backend/commands/tablecmds.c
src/backend/executor/spi.c
src/backend/parser/gram.y
src/backend/parser/parse_coerce.c
src/backend/parser/parse_type.c
src/backend/parser/parser.c
src/backend/tcop/postgres.c
src/include/executor/spi.h
src/include/executor/spi_priv.h
src/include/parser/parser.h
src/interfaces/ecpg/preproc/parse.pl
src/pl/plpgsql/src/pl_exec.c
src/pl/plpgsql/src/pl_gram.y

index 6e92e15ca3b3fbdba908a4cad109b9c0175ed2c1..f5e0a35da0645e6b20c342d5aa5a68ff1dbebec4 100644 (file)
@@ -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>
index 11dae782fd2f5bdbb7eeec0b0bdadbb2d815f552..993da56d437c9fcd394fd5d4c23b2ff3109435dc 100644 (file)
@@ -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)
        {
index 8368ead1ef6c17ed6eff59f8c44a807ac00ab2b4..6c0593686a9573ac7caf68460b1a851c9d15c362 100644 (file)
@@ -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;
@@ -784,6 +788,42 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
        return result;
 }
 
+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,
@@ -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)
index 18e181d5005dfd88544fbed61d4a86066ee94694..fb025f08a4eb415e3c60620845f4cb34a588af30 100644 (file)
@@ -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);
+                       }
                ;
 
 /*
index 8d01fca6d21783aaf65bf5b03ddc4e1d95f90d15..74eb39c0e4d8d5bce67e45b7a9282006cd1e5892 100644 (file)
@@ -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;
                        }
index 717125ad87388fbdc3551c53ea554627677f3c45..abe131ebebfc2d4f71d17dfc4d7f31900229c804 100644 (file)
@@ -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:
index b897a5160a22cba3c5e80a010f7c94d592067b97..8eb8feb372ee652bfd60aa3a43fe8d464737ffce 100644 (file)
@@ -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
index dfa0d685a837a67f23ec801a8ece6c4487747638..f5c14249d13db156f68b6db433458a202a29dced 100644 (file)
@@ -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");
index 6e603d007d73615ab663e5e6198f735b0ec92659..9c70603434a20ad0604aa066555188d7678bf506 100644 (file)
@@ -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,
index 29a77781a9d5715dee9ca804745cf866774e99a0..ce0f58ce687b075a6995d5a5fe53d23164503dee 100644 (file)
@@ -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) */
index 0973003044498287dd84bd9b6b31af3d31459269..80d90027cc47b6978fd2f7f619970ba1c77a7937 100644 (file)
 #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);
index f2731ea873a43f6a8ea29cceab879447146e8a07..7f9be85eb66edd19f6d4a5edb9c48c9ba85a66f7 100644 (file)
@@ -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',
index f966ddf0b5e37f20cd13ba9754ae890fb56c23b8..4a51fb6d9f101d2d12c8b046a8781bd811768faf 100644 (file)
@@ -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);
index a154b9841a65c3fb896e6ba817f84609011d69a6..c09576efff501058277b4338758e74978b9c7117 100644 (file)
@@ -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 */