diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index 7bc5be1565f..92f32768f84 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -2991,8 +2991,10 @@ query_or_expression_tree_mutator(Node *node, * Unlike expression_tree_walker, there is no special rule about query * boundaries: we descend to everything that's possibly interesting. * - * Currently, the node type coverage extends to SelectStmt and everything - * that could appear under it, but not other statement types. + * Currently, the node type coverage here extends only to DML statements + * (SELECT/INSERT/UPDATE/DELETE) and nodes that can appear in them, because + * this is used mainly during analysis of CTEs, and only DML statements can + * appear in CTEs. */ bool raw_expression_tree_walker(Node *node, diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 7d2fedfaadf..29c8c4e94c7 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -74,6 +74,9 @@ static Query *transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt); static void transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, bool pushedDown); +#ifdef RAW_EXPRESSION_COVERAGE_TEST +static bool test_raw_expression_coverage(Node *node, void *context); +#endif /* @@ -220,6 +223,25 @@ transformStmt(ParseState *pstate, Node *parseTree) { Query *result; + /* + * We apply RAW_EXPRESSION_COVERAGE_TEST testing to basic DML statements; + * we can't just run it on everything because raw_expression_tree_walker() + * doesn't claim to handle utility statements. + */ +#ifdef RAW_EXPRESSION_COVERAGE_TEST + switch (nodeTag(parseTree)) + { + case T_SelectStmt: + case T_InsertStmt: + case T_UpdateStmt: + case T_DeleteStmt: + (void) test_raw_expression_coverage(parseTree, NULL); + break; + default: + break; + } +#endif /* RAW_EXPRESSION_COVERAGE_TEST */ + switch (nodeTag(parseTree)) { /* @@ -2713,3 +2735,25 @@ applyLockingClause(Query *qry, Index rtindex, rc->pushedDown = pushedDown; qry->rowMarks = lappend(qry->rowMarks, rc); } + +/* + * Coverage testing for raw_expression_tree_walker(). + * + * When enabled, we run raw_expression_tree_walker() over every DML statement + * submitted to parse analysis. Without this provision, that function is only + * applied in limited cases involving CTEs, and we don't really want to have + * to test everything inside as well as outside a CTE. + */ +#ifdef RAW_EXPRESSION_COVERAGE_TEST + +static bool +test_raw_expression_coverage(Node *node, void *context) +{ + if (node == NULL) + return false; + return raw_expression_tree_walker(node, + test_raw_expression_coverage, + context); +} + +#endif /* RAW_EXPRESSION_COVERAGE_TEST */ diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h index 8d5a3783876..a2b2b614bec 100644 --- a/src/include/pg_config_manual.h +++ b/src/include/pg_config_manual.h @@ -273,6 +273,13 @@ */ /* #define COPY_PARSE_PLAN_TREES */ +/* + * Define this to force all raw parse trees for DML statements to be scanned + * by raw_expression_tree_walker(), to facilitate catching errors and + * omissions in that function. + */ +/* #define RAW_EXPRESSION_COVERAGE_TEST */ + /* * Enable debugging print statements for lock-related operations. */