Skip to content

Commit d47fff3

Browse files
committed
Explicitly support the case that a plancache's raw_parse_tree is NULL.
This only happens if a client issues a Parse message with an empty query string, which is a bit odd; but since it is explicitly called out as legal by our FE/BE protocol spec, we'd probably better continue to allow it. Fix by adding tests everywhere that the raw_parse_tree field is passed to functions that don't or shouldn't accept NULL. Also make it clear in the relevant comments that NULL is an expected case. This reverts commits a73c9db and 2e9650c, which fixed specific crash symptoms by hacking things at what now seems to be the wrong end, ie the callee functions. Making the callees allow NULL is superficially more robust, but it's not always true that there is a defensible thing for the callee to do in such cases. The caller has more context and is better able to decide what the empty-query case ought to do. Per followup discussion of bug #11335. Back-patch to 9.2. The code before that is sufficiently different that it would require development of a separate patch, which doesn't seem worthwhile for what is believed to be an essentially cosmetic change.
1 parent 4a9710e commit d47fff3

File tree

6 files changed

+15
-15
lines changed

6 files changed

+15
-15
lines changed

src/backend/executor/spi.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1942,7 +1942,9 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
19421942
* Parameter datatypes are driven by parserSetup hook if provided,
19431943
* otherwise we use the fixed parameter list.
19441944
*/
1945-
if (plan->parserSetup != NULL)
1945+
if (parsetree == NULL)
1946+
stmt_list = NIL;
1947+
else if (plan->parserSetup != NULL)
19461948
{
19471949
Assert(plan->nargs == 0);
19481950
stmt_list = pg_analyze_and_rewrite_params(parsetree,

src/backend/parser/analyze.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,17 +287,13 @@ transformStmt(ParseState *pstate, Node *parseTree)
287287
* Returns true if a snapshot must be set before doing parse analysis
288288
* on the given raw parse tree.
289289
*
290-
* Classification here should match transformStmt(); but we also have to
291-
* allow a NULL input (for Parse/Bind of an empty query string).
290+
* Classification here should match transformStmt().
292291
*/
293292
bool
294293
analyze_requires_snapshot(Node *parseTree)
295294
{
296295
bool result;
297296

298-
if (parseTree == NULL)
299-
return false;
300-
301297
switch (nodeTag(parseTree))
302298
{
303299
/*

src/backend/tcop/postgres.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,9 @@ exec_bind_message(StringInfo input_message)
15471547
* snapshot active till we're done, so that plancache.c doesn't have to
15481548
* take new ones.
15491549
*/
1550-
if (numParams > 0 || analyze_requires_snapshot(psrc->raw_parse_tree))
1550+
if (numParams > 0 ||
1551+
(psrc->raw_parse_tree &&
1552+
analyze_requires_snapshot(psrc->raw_parse_tree)))
15511553
{
15521554
PushActiveSnapshot(GetTransactionSnapshot());
15531555
snapshot_set = true;

src/backend/tcop/utility.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2184,9 +2184,6 @@ GetCommandLogLevel(Node *parsetree)
21842184
{
21852185
LogStmtLevel lev;
21862186

2187-
if (parsetree == NULL)
2188-
return LOGSTMT_ALL;
2189-
21902187
switch (nodeTag(parsetree))
21912188
{
21922189
/* raw plannable queries */
@@ -2290,7 +2287,7 @@ GetCommandLogLevel(Node *parsetree)
22902287

22912288
/* Look through an EXECUTE to the referenced stmt */
22922289
ps = FetchPreparedStatement(stmt->name, false);
2293-
if (ps)
2290+
if (ps && ps->plansource->raw_parse_tree)
22942291
lev = GetCommandLogLevel(ps->plansource->raw_parse_tree);
22952292
else
22962293
lev = LOGSTMT_ALL;

src/backend/utils/cache/plancache.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ InitPlanCache(void)
136136
* Once constructed, the cached plan can be made longer-lived, if needed,
137137
* by calling SaveCachedPlan.
138138
*
139-
* raw_parse_tree: output of raw_parser()
139+
* raw_parse_tree: output of raw_parser(), or NULL if empty query
140140
* query_string: original query text
141141
* commandTag: compile-time-constant tag for query, or NULL if empty query
142142
*/
@@ -218,7 +218,7 @@ CreateCachedPlan(Node *raw_parse_tree,
218218
* invalidation, so plan use must be completed in the current transaction,
219219
* and DDL that might invalidate the querytree_list must be avoided as well.
220220
*
221-
* raw_parse_tree: output of raw_parser()
221+
* raw_parse_tree: output of raw_parser(), or NULL if empty query
222222
* query_string: original query text
223223
* commandTag: compile-time-constant tag for query, or NULL if empty query
224224
*/
@@ -644,7 +644,9 @@ RevalidateCachedQuery(CachedPlanSource *plansource)
644644
* the cache.
645645
*/
646646
rawtree = copyObject(plansource->raw_parse_tree);
647-
if (plansource->parserSetup != NULL)
647+
if (rawtree == NULL)
648+
tlist = NIL;
649+
else if (plansource->parserSetup != NULL)
648650
tlist = pg_analyze_and_rewrite_params(rawtree,
649651
plansource->query_string,
650652
plansource->parserSetup,
@@ -883,6 +885,7 @@ BuildCachedPlan(CachedPlanSource *plansource, List *qlist,
883885
*/
884886
snapshot_set = false;
885887
if (!ActiveSnapshotSet() &&
888+
plansource->raw_parse_tree &&
886889
analyze_requires_snapshot(plansource->raw_parse_tree))
887890
{
888891
PushActiveSnapshot(GetTransactionSnapshot());

src/include/utils/plancache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
typedef struct CachedPlanSource
7777
{
7878
int magic; /* should equal CACHEDPLANSOURCE_MAGIC */
79-
Node *raw_parse_tree; /* output of raw_parser() */
79+
Node *raw_parse_tree; /* output of raw_parser(), or NULL */
8080
const char *query_string; /* source text of query */
8181
const char *commandTag; /* command tag (a constant!), or NULL */
8282
Oid *param_types; /* array of parameter type OIDs, or NULL */

0 commit comments

Comments
 (0)