I have found some of the parse/analyze API calls confusing one too many
times, so here I'm proposing some renaming and refactoring.
Notionally, there are three parallel ways to call the parse/analyze
phase: with fixed parameters (for example, used by SPI), with variable
parameters (for example, used by PREPARE), and with a parser callback
(for example, used to parse the body of SQL functions). Some of the
involved functions were confusingly named and made this API structure
more confusing.
For example, at the top level there are pg_analyze_and_rewrite() and
pg_analyze_and_rewrite_params(). You'd think the first one doesn't take
parameters and the second one takes parameters. But the truth is, the
first one takes fixed parameters and the second one takes a parser
callback. The parser callback can be used to parse parameters, but also
other things. There isn't any variant that takes variable parameters;
that code is sprinkled around other places altogether.
One level below that, there is parse_analyze() (for fixed parameters)
and parse_analyze_varparams() (good name). But there is no analogous
function for the callback variant; that code is spread out in
pg_analyze_and_rewrite_params().
And then there are parse_fixed_parameters() and
parse_variable_parameters(). But they don't do any parsing at all.
They just set up callbacks for the parsing to follow.
This doesn't need to be so confusing. With the attached patch set, the
calls end up:
pg_analyze_and_rewrite_fixedparams()
-> parse_analyze_fixedparams()
-> setup_parse_fixed_parameters()
pg_analyze_and_rewrite_varparams() [new]
-> parse_analyze_varparams()
-> setup_parse_variable_parameters()
pg_analyze_and_rewrite_withcb()
-> parse_analyze_withcb() [new]
-> (nothing needed here)
(The "withcb" naming maybe isn't great; better ideas welcome.)
Not included in this patch set, but food for further thought: The
pg_analyze_and_rewrite_*() functions aren't all that useful (anymore).
One might as well write
pg_rewrite_query(parse_analyze_xxx(...))
The only things that pg_analyze_and_rewrite_*() do in addition to that
is handle log_parser_stats, which could be moved into parse_analyze_*(),
and TRACE_POSTGRESQL_QUERY_REWRITE_*(), which IMO doesn't make sense to
begin with and should be in pg_rewrite_query().From 9a72ceadebd6b9309fe0157c1cd181b29ee8bd52 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Tue, 28 Dec 2021 09:01:45 +0100
Subject: [PATCH v1 1/3] Parse/analyze function renaming
There are three parallel ways to call parse/analyze: with fixed
parameters, with variable parameters, and by supplying your own parser
callback. Some of the involved functions were confusingly named and
made this API structure more confusing. This patch renames some functions to
make this clearer:
parse_analyze() -> parse_analyze_fixedparams()
pg_analyze_and_rewrite() -> pg_analyze_and_rewrite_fixedparams()
(Otherwise one might think this variant doesn't accept parameters, but
in fact all three ways accept parameters.)
pg_analyze_and_rewrite_params() -> pg_analyze_and_rewrite_withcb()
(Before, and also when considering pg_analyze_and_rewrite(), one might
think this is the only way to pass parameters. Moreover, the parser
callback doesn't necessarily need to parse only parameters, it's just
one of the things it could do.)
parse_fixed_parameters() -> setup_parse_fixed_parameters()
parse_variable_parameters() -> setup_parse_variable_parameters()
(These functions don't actually do any parsing, they just set up
callbacks to use during parsing later.)
This patch also adds some const decorations to the fixed-parameters
API, so the distinction from the variable-parameters API is more
clear.
---
src/backend/catalog/pg_proc.c | 2 +-
src/backend/commands/copyto.c | 2 +-
src/backend/commands/extension.c | 2 +-
src/backend/commands/schemacmds.c | 2 +-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/view.c | 2 +-
src/backend/executor/functions.c | 2 +-
src/backend/executor/spi.c | 8 ++++----
src/backend/optimizer/util/clauses.c | 2 +-
src/backend/parser/analyze.c | 10 +++++-----
src/backend/parser/parse_param.c | 8 ++++----
src/backend/parser/parse_utilcmd.c | 2 +-
src/backend/tcop/postgres.c | 17 +++++++++--------
src/backend/utils/cache/plancache.c | 4 ++--
src/include/parser/analyze.h | 4 ++--
src/include/parser/parse_param.h | 6 +++---
src/include/tcop/tcopprot.h | 6 +++---
17 files changed, 41 insertions(+), 40 deletions(-)
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 25d35230d0..8dffcb3a19 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -947,7 +947,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
RawStmt *parsetree =
lfirst_node(RawStmt, lc);
List *querytree_sublist;
- querytree_sublist =
pg_analyze_and_rewrite_params(parsetree,
+ querytree_sublist =
pg_analyze_and_rewrite_withcb(parsetree,
prosrc,
(ParserSetupHook)
sql_fn_parser_setup,
pinfo,
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index b6eacd5baa..378f2b232d 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -439,7 +439,7 @@ BeginCopyTo(ParseState *pstate,
* Run parse analysis and rewrite. Note this also acquires
sufficient
* locks on the source table(s).
*/
- rewritten = pg_analyze_and_rewrite(raw_query,
+ rewritten = pg_analyze_and_rewrite_fixedparams(raw_query,
pstate->p_sourcetext, NULL, 0,
NULL);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index eaa76af47b..46b8ca9a00 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -746,7 +746,7 @@ execute_sql_string(const char *sql)
/* Be sure parser can see any DDL done so far */
CommandCounterIncrement();
- stmt_list = pg_analyze_and_rewrite(parsetree,
+ stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree,
sql,
NULL,
0,
diff --git a/src/backend/commands/schemacmds.c
b/src/backend/commands/schemacmds.c
index 6c6ab9ee34..0c376e070d 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -172,7 +172,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char
*queryString,
/*
* Execute each command contained in the CREATE SCHEMA. Since the
grammar
* allows only utility commands in CREATE SCHEMA, there is no need to
pass
- * them through parse_analyze() or the rewriter; we can just hand them
+ * them through parse_analyze_*() or the rewriter; we can just hand them
* straight to ProcessUtility.
*/
foreach(parsetree_item, parsetree_list)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 45e59e3d5c..41b0eac97a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -12920,7 +12920,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid
refRelId, char *cmd,
/*
* We expect that we will get only ALTER TABLE and CREATE INDEX
* statements. Hence, there is no need to pass them through
- * parse_analyze() or the rewriter, but instead we need to pass them
+ * 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_PARSE_DEFAULT);
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 4df05a0b33..8b6254cfce 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -423,7 +423,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
rawstmt->stmt_location = stmt_location;
rawstmt->stmt_len = stmt_len;
- viewParse = parse_analyze(rawstmt, queryString, NULL, 0, NULL);
+ viewParse = parse_analyze_fixedparams(rawstmt, queryString, NULL, 0,
NULL);
/*
* The grammar should ensure that the result is a single SELECT Query.
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 296e54e60a..fd878555ee 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -718,7 +718,7 @@ init_sql_fcache(FunctionCallInfo fcinfo, Oid collation,
bool lazyEvalOK)
RawStmt *parsetree = lfirst_node(RawStmt, lc);
List *queryTree_sublist;
- queryTree_sublist =
pg_analyze_and_rewrite_params(parsetree,
+ queryTree_sublist =
pg_analyze_and_rewrite_withcb(parsetree,
fcache->src,
(ParserSetupHook) sql_fn_parser_setup,
fcache->pinfo,
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 0568ae123f..95989f237d 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -2165,7 +2165,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
if (plan->parserSetup != NULL)
{
Assert(plan->nargs == 0);
- stmt_list = pg_analyze_and_rewrite_params(parsetree,
+ stmt_list = pg_analyze_and_rewrite_withcb(parsetree,
src,
plan->parserSetup,
plan->parserSetupArg,
@@ -2173,7 +2173,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
}
else
{
- stmt_list = pg_analyze_and_rewrite(parsetree,
+ stmt_list =
pg_analyze_and_rewrite_fixedparams(parsetree,
src,
plan->argtypes,
plan->nargs,
@@ -2402,7 +2402,7 @@ _SPI_execute_plan(SPIPlanPtr plan, const
SPIExecuteOptions *options,
else if (plan->parserSetup != NULL)
{
Assert(plan->nargs == 0);
- stmt_list =
pg_analyze_and_rewrite_params(parsetree,
+ stmt_list =
pg_analyze_and_rewrite_withcb(parsetree,
src,
plan->parserSetup,
plan->parserSetupArg,
@@ -2410,7 +2410,7 @@ _SPI_execute_plan(SPIPlanPtr plan, const
SPIExecuteOptions *options,
}
else
{
- stmt_list = pg_analyze_and_rewrite(parsetree,
+ stmt_list =
pg_analyze_and_rewrite_fixedparams(parsetree,
src,
plan->argtypes,
plan->nargs,
diff --git a/src/backend/optimizer/util/clauses.c
b/src/backend/optimizer/util/clauses.c
index 873e43bfe6..94735cf0e8 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -5057,7 +5057,7 @@ inline_set_returning_function(PlannerInfo *root,
RangeTblEntry *rte)
if (list_length(raw_parsetree_list) != 1)
goto fail;
- querytree_list =
pg_analyze_and_rewrite_params(linitial(raw_parsetree_list),
+ querytree_list =
pg_analyze_and_rewrite_withcb(linitial(raw_parsetree_list),
src,
(ParserSetupHook) sql_fn_parser_setup,
pinfo, NULL);
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 146ee8dd1e..56c58d263d 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -96,7 +96,7 @@ static bool test_raw_expression_coverage(Node *node, void
*context);
/*
- * parse_analyze
+ * parse_analyze_fixedparams
* Analyze a raw parse tree and transform it to Query form.
*
* Optionally, information about $n parameter types can be supplied.
@@ -107,8 +107,8 @@ static bool test_raw_expression_coverage(Node *node, void
*context);
* a dummy CMD_UTILITY Query node.
*/
Query *
-parse_analyze(RawStmt *parseTree, const char *sourceText,
- Oid *paramTypes, int numParams,
+parse_analyze_fixedparams(RawStmt *parseTree, const char *sourceText,
+ const Oid *paramTypes, int numParams,
QueryEnvironment *queryEnv)
{
ParseState *pstate = make_parsestate(NULL);
@@ -120,7 +120,7 @@ parse_analyze(RawStmt *parseTree, const char *sourceText,
pstate->p_sourcetext = sourceText;
if (numParams > 0)
- parse_fixed_parameters(pstate, paramTypes, numParams);
+ setup_parse_fixed_parameters(pstate, paramTypes, numParams);
pstate->p_queryEnv = queryEnv;
@@ -158,7 +158,7 @@ parse_analyze_varparams(RawStmt *parseTree, const char
*sourceText,
pstate->p_sourcetext = sourceText;
- parse_variable_parameters(pstate, paramTypes, numParams);
+ setup_parse_variable_parameters(pstate, paramTypes, numParams);
query = transformTopLevelStmt(pstate, parseTree);
diff --git a/src/backend/parser/parse_param.c b/src/backend/parser/parse_param.c
index 68a5534393..b9726e0757 100644
--- a/src/backend/parser/parse_param.c
+++ b/src/backend/parser/parse_param.c
@@ -35,7 +35,7 @@
typedef struct FixedParamState
{
- Oid *paramTypes; /* array of parameter type OIDs
*/
+ const Oid *paramTypes; /* array of parameter type OIDs */
int numParams; /* number of array
entries */
} FixedParamState;
@@ -64,8 +64,8 @@ static bool query_contains_extern_params_walker(Node *node,
void *context);
* Set up to process a query containing references to fixed parameters.
*/
void
-parse_fixed_parameters(ParseState *pstate,
- Oid *paramTypes, int numParams)
+setup_parse_fixed_parameters(ParseState *pstate,
+ const Oid *paramTypes, int numParams)
{
FixedParamState *parstate = palloc(sizeof(FixedParamState));
@@ -80,7 +80,7 @@ parse_fixed_parameters(ParseState *pstate,
* Set up to process a query containing references to variable parameters.
*/
void
-parse_variable_parameters(ParseState *pstate,
+setup_parse_variable_parameters(ParseState *pstate,
Oid **paramTypes, int
*numParams)
{
VarParamState *parstate = palloc(sizeof(VarParamState));
diff --git a/src/backend/parser/parse_utilcmd.c
b/src/backend/parser/parse_utilcmd.c
index 2d857a301b..464dc6c31b 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3,7 +3,7 @@
* parse_utilcmd.c
* Perform parse analysis work for various utility commands
*
- * Formerly we did this work during parse_analyze() in analyze.c. However
+ * Formerly we did this work during parse_analyze_*() in analyze.c. However
* that is fairly unsafe in the presence of querytree caching, since any
* database state that we depend on in making the transformations might be
* obsolete by the time the utility command is executed; and utility commands
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 82de01cdc6..e86275c781 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -640,8 +640,8 @@ pg_parse_query(const char *query_string)
* NOTE: for reasons mentioned above, this must be separate from raw parsing.
*/
List *
-pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string,
- Oid *paramTypes, int numParams,
+pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char
*query_string,
+ const Oid *paramTypes, int numParams,
QueryEnvironment *queryEnv)
{
Query *query;
@@ -655,7 +655,7 @@ pg_analyze_and_rewrite(RawStmt *parsetree, const char
*query_string,
if (log_parser_stats)
ResetUsage();
- query = parse_analyze(parsetree, query_string, paramTypes, numParams,
+ query = parse_analyze_fixedparams(parsetree, query_string, paramTypes,
numParams,
queryEnv);
if (log_parser_stats)
@@ -672,12 +672,13 @@ pg_analyze_and_rewrite(RawStmt *parsetree, const char
*query_string,
}
/*
- * Do parse analysis and rewriting. This is the same as pg_analyze_and_rewrite
- * except that external-parameter resolution is determined by parser callback
- * hooks instead of a fixed list of parameter datatypes.
+ * Do parse analysis and rewriting. This is the same as
+ * pg_analyze_and_rewrite_* except that, instead of a fixed list of parameter
+ * datatypes, a parser callback is supplied that can do external-parameter
+ * resolution and possibly other things.
*/
List *
-pg_analyze_and_rewrite_params(RawStmt *parsetree,
+pg_analyze_and_rewrite_withcb(RawStmt *parsetree,
const char
*query_string,
ParserSetupHook
parserSetup,
void *parserSetupArg,
@@ -1128,7 +1129,7 @@ exec_simple_query(const char *query_string)
else
oldcontext = MemoryContextSwitchTo(MessageContext);
- querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
+ querytree_list = pg_analyze_and_rewrite_fixedparams(parsetree,
query_string,
NULL, 0, NULL);
plantree_list = pg_plan_queries(querytree_list, query_string,
diff --git a/src/backend/utils/cache/plancache.c
b/src/backend/utils/cache/plancache.c
index 6767eae8f2..28871f0176 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -682,13 +682,13 @@ RevalidateCachedQuery(CachedPlanSource *plansource,
if (rawtree == NULL)
tlist = NIL;
else if (plansource->parserSetup != NULL)
- tlist = pg_analyze_and_rewrite_params(rawtree,
+ tlist = pg_analyze_and_rewrite_withcb(rawtree,
plansource->query_string,
plansource->parserSetup,
plansource->parserSetupArg,
queryEnv);
else
- tlist = pg_analyze_and_rewrite(rawtree,
+ tlist = pg_analyze_and_rewrite_fixedparams(rawtree,
plansource->query_string,
plansource->param_types,
plansource->num_params,
diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h
index a0f0bd38d7..e019bc9b1e 100644
--- a/src/include/parser/analyze.h
+++ b/src/include/parser/analyze.h
@@ -24,8 +24,8 @@ typedef void (*post_parse_analyze_hook_type) (ParseState
*pstate,
extern PGDLLIMPORT post_parse_analyze_hook_type post_parse_analyze_hook;
-extern Query *parse_analyze(RawStmt *parseTree, const char *sourceText,
- Oid *paramTypes, int
numParams, QueryEnvironment *queryEnv);
+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);
diff --git a/src/include/parser/parse_param.h b/src/include/parser/parse_param.h
index b42fff296c..e7069df6ac 100644
--- a/src/include/parser/parse_param.h
+++ b/src/include/parser/parse_param.h
@@ -15,9 +15,9 @@
#include "parser/parse_node.h"
-extern void parse_fixed_parameters(ParseState *pstate,
- Oid
*paramTypes, int numParams);
-extern void parse_variable_parameters(ParseState *pstate,
+extern void setup_parse_fixed_parameters(ParseState *pstate,
+ const Oid
*paramTypes, int numParams);
+extern void setup_parse_variable_parameters(ParseState *pstate,
Oid
**paramTypes, int *numParams);
extern void check_variable_parameters(ParseState *pstate, Query *query);
extern bool query_contains_extern_params(Query *query);
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 5c77075aed..af056fe43a 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -45,11 +45,11 @@ extern PGDLLIMPORT int log_statement;
extern List *pg_parse_query(const char *query_string);
extern List *pg_rewrite_query(Query *query);
-extern List *pg_analyze_and_rewrite(RawStmt *parsetree,
+extern List *pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree,
const
char *query_string,
- Oid
*paramTypes, int numParams,
+ const
Oid *paramTypes, int numParams,
QueryEnvironment *queryEnv);
-extern List *pg_analyze_and_rewrite_params(RawStmt *parsetree,
+extern List *pg_analyze_and_rewrite_withcb(RawStmt *parsetree,
const char *query_string,
ParserSetupHook parserSetup,
void *parserSetupArg,
base-commit: cab5b9ab2c066ba904f13de2681872dcda31e207
--
2.34.1
From b1e36d4b49cc37138cecbbd9c1f128f9c1df65f4 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Tue, 28 Dec 2021 09:01:45 +0100
Subject: [PATCH v1 2/3] Add pg_analyze_and_rewrite_varparams()
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.
---
src/backend/commands/prepare.c | 43 ++-------------
src/backend/parser/analyze.c | 5 +-
src/backend/tcop/postgres.c | 95 +++++++++++++++++++++++-----------
src/include/parser/analyze.h | 2 +-
src/include/tcop/tcopprot.h | 5 ++
5 files changed, 78 insertions(+), 72 deletions(-)
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 5e03c7c5aa..9d0d27184c 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -62,9 +62,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
@@ -96,6 +94,7 @@ PrepareQuery(ParseState *pstate, PrepareStmt *stmt,
if (nargs)
{
+ int i;
ListCell *l;
argtypes = (Oid *) palloc(nargs * sizeof(Oid));
@@ -114,44 +113,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,
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 56c58d263d..4a9d212b22 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -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 */
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index e86275c781..8ade13994f 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -640,9 +640,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;
@@ -671,6 +673,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_* except that, instead of a fixed list of parameter
@@ -1412,7 +1467,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);
@@ -1452,34 +1506,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,
-
¶mTypes,
-
&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,
+
¶mTypes,
+
&numParams,
+
NULL);
/* Done with the snapshot used for parsing */
if (snapshot_set)
diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h
index e019bc9b1e..b1c592c6c6 100644
--- a/src/include/parser/analyze.h
+++ b/src/include/parser/analyze.h
@@ -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,
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index af056fe43a..37bce8cdb5 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -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,
--
2.34.1
From 9baad5def3d9a4b442a591b9f6286044c354f89d Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Tue, 28 Dec 2021 09:01:45 +0100
Subject: [PATCH v1 3/3] Add parse_analyze_withcb()
This extracts code from pg_analyze_and_rewrite_withcb() into a
separate function that mirrors the existing
parse_analyze_fixedparams() and parse_analyze_varparams().
---
src/backend/parser/analyze.c | 38 ++++++++++++++++++++++++++++++++++++
src/backend/tcop/postgres.c | 22 ++-------------------
src/include/parser/analyze.h | 5 +++++
3 files changed, 45 insertions(+), 20 deletions(-)
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 4a9d212b22..6f4cc1b9db 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -181,6 +181,44 @@ parse_analyze_varparams(RawStmt *parseTree, const char
*sourceText,
return query;
}
+/*
+ * parse_analyze_withcb
+ *
+ * This variant is used when the caller supplies their own parser callback to
+ * resolve parameters and possibly other things.
+ */
+Query *
+parse_analyze_withcb(RawStmt *parseTree, const char *sourceText,
+ ParserSetupHook parserSetup,
+ void *parserSetupArg,
+ QueryEnvironment *queryEnv)
+{
+ ParseState *pstate = make_parsestate(NULL);
+ Query *query;
+ JumbleState *jstate = NULL;
+
+ Assert(sourceText != NULL); /* required as of 8.4 */
+
+ pstate->p_sourcetext = sourceText;
+ pstate->p_queryEnv = queryEnv;
+ (*parserSetup) (pstate, parserSetupArg);
+
+ query = transformTopLevelStmt(pstate, parseTree);
+
+ if (IsQueryIdEnabled())
+ jstate = JumbleQuery(query, sourceText);
+
+ if (post_parse_analyze_hook)
+ (*post_parse_analyze_hook) (pstate, query, jstate);
+
+ free_parsestate(pstate);
+
+ pgstat_report_query_id(query->queryId, false);
+
+ return query;
+}
+
+
/*
* parse_sub_analyze
* Entry point for recursively analyzing a sub-statement.
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 8ade13994f..a646e34d4c 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -739,12 +739,8 @@ pg_analyze_and_rewrite_withcb(RawStmt *parsetree,
void *parserSetupArg,
QueryEnvironment
*queryEnv)
{
- ParseState *pstate;
Query *query;
List *querytree_list;
- JumbleState *jstate = NULL;
-
- Assert(query_string != NULL); /* required as of 8.4 */
TRACE_POSTGRESQL_QUERY_REWRITE_START(query_string);
@@ -754,22 +750,8 @@ pg_analyze_and_rewrite_withcb(RawStmt *parsetree,
if (log_parser_stats)
ResetUsage();
- pstate = make_parsestate(NULL);
- pstate->p_sourcetext = query_string;
- pstate->p_queryEnv = queryEnv;
- (*parserSetup) (pstate, parserSetupArg);
-
- query = transformTopLevelStmt(pstate, parsetree);
-
- if (IsQueryIdEnabled())
- jstate = JumbleQuery(query, query_string);
-
- if (post_parse_analyze_hook)
- (*post_parse_analyze_hook) (pstate, query, jstate);
-
- free_parsestate(pstate);
-
- pgstat_report_query_id(query->queryId, false);
+ query = parse_analyze_withcb(parsetree, query_string, parserSetup,
parserSetupArg,
+ queryEnv);
if (log_parser_stats)
ShowUsage("PARSE ANALYSIS STATISTICS");
diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h
index b1c592c6c6..423b956869 100644
--- a/src/include/parser/analyze.h
+++ b/src/include/parser/analyze.h
@@ -14,6 +14,7 @@
#ifndef ANALYZE_H
#define ANALYZE_H
+#include "nodes/params.h"
#include "parser/parse_node.h"
#include "utils/queryjumble.h"
@@ -28,6 +29,10 @@ extern Query *parse_analyze_fixedparams(RawStmt *parseTree,
const char *sourceTe
const Oid *paramTypes,
int numParams, QueryEnvironment *queryEnv);
extern Query *parse_analyze_varparams(RawStmt *parseTree, const char
*sourceText,
Oid
**paramTypes, int *numParams, QueryEnvironment *queryEnv);
+extern Query *parse_analyze_withcb(RawStmt *parseTree, const char *sourceText,
+
ParserSetupHook parserSetup,
+ void
*parserSetupArg,
+
QueryEnvironment *queryEnv);
extern Query *parse_sub_analyze(Node *parseTree, ParseState *parentParseState,
CommonTableExpr
*parentCTE,
--
2.34.1