Add pg_analyze_and_rewrite_varparams()
authorPeter Eisentraut <peter@eisentraut.org>
Fri, 4 Mar 2022 13:49:37 +0000 (14:49 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Mon, 7 Mar 2022 07:13:30 +0000 (08:13 +0100)
This new function extracts common code from PrepareQuery() and
exec_parse_message().  It is then exactly analogous to the existing
pg_analyze_and_rewrite_fixedparams() and
pg_analyze_and_rewrite_withcb().

To unify these two code paths, this makes PrepareQuery() now subject
to log_parser_stats.  Also, both paths now invoke
TRACE_POSTGRESQL_QUERY_REWRITE_START().  PrepareQuery() no longer
checks whether a utility statement was specified.  The grammar doesn't
allow that anyway, and exec_parse_message() supports it, so
restricting it doesn't seem necessary.

This also adds QueryEnvironment support to the *varparams functions,
for consistency with its cousins, even though it is not used right
now.

Reviewed-by: Nathan Bossart <bossartn@amazon.com>
Discussion: https://www.postgresql.org/message-id/flat/c67ce276-52b4-0239-dc0e-39875bf81840@enterprisedb.com

src/backend/commands/prepare.c
src/backend/parser/analyze.c
src/backend/tcop/postgres.c
src/include/parser/analyze.h
src/include/tcop/tcopprot.h

index d2d8ee120c32c8365b7a13e679447dc4eb3f3e75..80738547ed80a8cdd259c785ae49cfc49db93104 100644 (file)
@@ -63,9 +63,7 @@ PrepareQuery(ParseState *pstate, PrepareStmt *stmt,
    CachedPlanSource *plansource;
    Oid        *argtypes = NULL;
    int         nargs;
-   Query      *query;
    List       *query_list;
-   int         i;
 
    /*
     * Disallow empty-string statement name (conflicts with protocol-level
@@ -97,6 +95,7 @@ PrepareQuery(ParseState *pstate, PrepareStmt *stmt,
 
    if (nargs)
    {
+       int         i;
        ListCell   *l;
 
        argtypes = (Oid *) palloc(nargs * sizeof(Oid));
@@ -115,44 +114,10 @@ PrepareQuery(ParseState *pstate, PrepareStmt *stmt,
     * Analyze the statement using these parameter types (any parameters
     * passed in from above us will not be visible to it), allowing
     * information about unknown parameters to be deduced from context.
+    * Rewrite the query. The result could be 0, 1, or many queries.
     */
-   query = parse_analyze_varparams(rawstmt, pstate->p_sourcetext,
-                                   &argtypes, &nargs);
-
-   /*
-    * Check that all parameter types were determined.
-    */
-   for (i = 0; i < nargs; i++)
-   {
-       Oid         argtype = argtypes[i];
-
-       if (argtype == InvalidOid || argtype == UNKNOWNOID)
-           ereport(ERROR,
-                   (errcode(ERRCODE_INDETERMINATE_DATATYPE),
-                    errmsg("could not determine data type of parameter $%d",
-                           i + 1)));
-   }
-
-   /*
-    * grammar only allows PreparableStmt, so this check should be redundant
-    */
-   switch (query->commandType)
-   {
-       case CMD_SELECT:
-       case CMD_INSERT:
-       case CMD_UPDATE:
-       case CMD_DELETE:
-           /* OK */
-           break;
-       default:
-           ereport(ERROR,
-                   (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
-                    errmsg("utility statements cannot be prepared")));
-           break;
-   }
-
-   /* Rewrite the query. The result could be 0, 1, or many queries. */
-   query_list = QueryRewrite(query);
+   query_list = pg_analyze_and_rewrite_varparams(rawstmt, pstate->p_sourcetext,
+                                                 &argtypes, &nargs, NULL);
 
    /* Finish filling in the CachedPlanSource */
    CompleteCachedPlan(plansource,
index 19d97fe731be1e2a5f6af5c91c82a91894c037e7..53c11b3a15644ee57718c26b7246dd64b48f83f7 100644 (file)
@@ -148,7 +148,8 @@ parse_analyze_fixedparams(RawStmt *parseTree, const char *sourceText,
  */
 Query *
 parse_analyze_varparams(RawStmt *parseTree, const char *sourceText,
-                       Oid **paramTypes, int *numParams)
+                       Oid **paramTypes, int *numParams,
+                       QueryEnvironment *queryEnv)
 {
    ParseState *pstate = make_parsestate(NULL);
    Query      *query;
@@ -160,6 +161,8 @@ parse_analyze_varparams(RawStmt *parseTree, const char *sourceText,
 
    setup_parse_variable_parameters(pstate, paramTypes, numParams);
 
+   pstate->p_queryEnv = queryEnv;
+
    query = transformTopLevelStmt(pstate, parseTree);
 
    /* make sure all is well with parameter types */
index c087db4445696dae854fc239fa7f60c26e3d2f31..d7e39aed64bceb3ba804710520f4fde6726e582b 100644 (file)
@@ -637,9 +637,11 @@ pg_parse_query(const char *query_string)
  * NOTE: for reasons mentioned above, this must be separate from raw parsing.
  */
 List *
-pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string,
-                      const Oid *paramTypes, int numParams,
-                      QueryEnvironment *queryEnv)
+pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree,
+                                  const char *query_string,
+                                  const Oid *paramTypes,
+                                  int numParams,
+                                  QueryEnvironment *queryEnv)
 {
    Query      *query;
    List       *querytree_list;
@@ -668,6 +670,59 @@ pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string,
    return querytree_list;
 }
 
+/*
+ * Do parse analysis and rewriting.  This is the same as
+ * pg_analyze_and_rewrite_fixedparams except that it's okay to deduce
+ * information about $n symbol datatypes from context.
+ */
+List *
+pg_analyze_and_rewrite_varparams(RawStmt *parsetree,
+                                const char *query_string,
+                                Oid **paramTypes,
+                                int *numParams,
+                                QueryEnvironment *queryEnv)
+{
+   Query      *query;
+   List       *querytree_list;
+
+   TRACE_POSTGRESQL_QUERY_REWRITE_START(query_string);
+
+   /*
+    * (1) Perform parse analysis.
+    */
+   if (log_parser_stats)
+       ResetUsage();
+
+   query = parse_analyze_varparams(parsetree, query_string, paramTypes, numParams,
+                         queryEnv);
+
+   /*
+    * Check all parameter types got determined.
+    */
+   for (int i = 0; i < *numParams; i++)
+   {
+       Oid         ptype = (*paramTypes)[i];
+
+       if (ptype == InvalidOid || ptype == UNKNOWNOID)
+           ereport(ERROR,
+                   (errcode(ERRCODE_INDETERMINATE_DATATYPE),
+                    errmsg("could not determine data type of parameter $%d",
+                           i + 1)));
+   }
+
+   if (log_parser_stats)
+       ShowUsage("PARSE ANALYSIS STATISTICS");
+
+   /*
+    * (2) Rewrite the queries, as necessary
+    */
+   querytree_list = pg_rewrite_query(query);
+
+   TRACE_POSTGRESQL_QUERY_REWRITE_DONE(query_string);
+
+   return querytree_list;
+}
+
 /*
  * Do parse analysis and rewriting.  This is the same as
  * pg_analyze_and_rewrite_fixedparams except that, instead of a fixed list of
@@ -1409,7 +1464,6 @@ exec_parse_message(const char *query_string,  /* string to execute */
 
    if (parsetree_list != NIL)
    {
-       Query      *query;
        bool        snapshot_set = false;
 
        raw_parse_tree = linitial_node(RawStmt, parsetree_list);
@@ -1449,34 +1503,13 @@ exec_parse_message(const char *query_string,    /* string to execute */
        /*
         * Analyze and rewrite the query.  Note that the originally specified
         * parameter set is not required to be complete, so we have to use
-        * parse_analyze_varparams().
-        */
-       if (log_parser_stats)
-           ResetUsage();
-
-       query = parse_analyze_varparams(raw_parse_tree,
-                                       query_string,
-                                       &paramTypes,
-                                       &numParams);
-
-       /*
-        * Check all parameter types got determined.
+        * pg_analyze_and_rewrite_varparams().
         */
-       for (int i = 0; i < numParams; i++)
-       {
-           Oid         ptype = paramTypes[i];
-
-           if (ptype == InvalidOid || ptype == UNKNOWNOID)
-               ereport(ERROR,
-                       (errcode(ERRCODE_INDETERMINATE_DATATYPE),
-                        errmsg("could not determine data type of parameter $%d",
-                               i + 1)));
-       }
-
-       if (log_parser_stats)
-           ShowUsage("PARSE ANALYSIS STATISTICS");
-
-       querytree_list = pg_rewrite_query(query);
+       querytree_list = pg_analyze_and_rewrite_varparams(raw_parse_tree,
+                                                         query_string,
+                                                         &paramTypes,
+                                                         &numParams,
+                                                         NULL);
 
        /* Done with the snapshot used for parsing */
        if (snapshot_set)
index ed989bb1413a6a4be03a9d25e7adc10b33173ec2..06b237c39c7ab268371a210b462f21b6302af7a3 100644 (file)
@@ -27,7 +27,7 @@ extern PGDLLIMPORT post_parse_analyze_hook_type post_parse_analyze_hook;
 extern Query *parse_analyze_fixedparams(RawStmt *parseTree, const char *sourceText,
                            const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv);
 extern Query *parse_analyze_varparams(RawStmt *parseTree, const char *sourceText,
-                                     Oid **paramTypes, int *numParams);
+                                     Oid **paramTypes, int *numParams, QueryEnvironment *queryEnv);
 
 extern Query *parse_sub_analyze(Node *parseTree, ParseState *parentParseState,
                                CommonTableExpr *parentCTE,
index 00c20966ab89db4ecfbeb8842a8ac799b9cc88f9..92291a750d38cddbc1d8ac1f6e6a3008ae3f344a 100644 (file)
@@ -49,6 +49,11 @@ extern List *pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree,
                                    const char *query_string,
                                    const Oid *paramTypes, int numParams,
                                    QueryEnvironment *queryEnv);
+extern List *pg_analyze_and_rewrite_varparams(RawStmt *parsetree,
+                                             const char *query_string,
+                                             Oid **paramTypes,
+                                             int *numParams,
+                                             QueryEnvironment *queryEnv);
 extern List *pg_analyze_and_rewrite_withcb(RawStmt *parsetree,
                                           const char *query_string,
                                           ParserSetupHook parserSetup,