From 734b893435adf9c1238dd53799fd4995b81264d0 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Fri, 26 Jan 2024 16:36:01 +0000 Subject: [PATCH 1/6] [BABEL-4673] Support View usage for PIVOT operator This commit fixed an issue that view cannot be created or used by stmt with pivot operator. Task: BABEL-4673 Signed-off-by: Yanjie Xu --- src/backend/executor/functions.c | 2 ++ src/backend/optimizer/plan/planner.c | 6 +++++- src/backend/parser/analyze.c | 22 +++++++++++++++++++++- src/backend/parser/parse_utilcmd.c | 2 ++ src/backend/rewrite/rewriteHandler.c | 13 +++++++++++++ src/backend/rewrite/rewriteSearchCycle.c | 4 ++++ src/include/nodes/parsenodes.h | 3 +++ src/include/parser/analyze.h | 2 +- src/include/rewrite/rewriteHandler.h | 4 ++++ 9 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index f55424eb5ad..1d457d45f13 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -1936,6 +1936,8 @@ check_sql_fn_retval(List *queryTreeLists, newquery->querySource = parse->querySource; newquery->canSetTag = true; newquery->targetList = upper_tlist; + newquery->isPivot = false; + newquery->pivotInfoList = NIL; /* We need a moderately realistic colnames list for the subquery RTE */ colnames = NIL; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 36cd8fbb238..22794989baa 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -6553,6 +6553,8 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) /* Set up mostly-dummy planner state */ query = makeNode(Query); query->commandType = CMD_SELECT; + query->isPivot = false; + query->pivotInfoList = NIL; glob = makeNode(PlannerGlobal); @@ -6675,7 +6677,9 @@ plan_create_index_workers(Oid tableOid, Oid indexOid) /* Set up largely-dummy planner state */ query = makeNode(Query); query->commandType = CMD_SELECT; - + query->isPivot = false; + query->pivotInfoList = NIL; + glob = makeNode(PlannerGlobal); root = makeNode(PlannerInfo); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 39a62e0b75b..e01c2f79804 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -407,11 +407,23 @@ transformStmt(ParseState *pstate, Node *parseTree) SelectStmt *n = (SelectStmt *) parseTree; if (n->valuesLists) + { result = transformValuesClause(pstate, n); + result->isPivot = false; + result->pivotInfoList = NIL; + } + else if (n->op == SETOP_NONE) + { result = transformSelectStmt(pstate, n); + } else + { result = transformSetOperationStmt(pstate, n); + result->isPivot = false; + result->pivotInfoList = NIL; + } + } break; @@ -459,6 +471,11 @@ transformStmt(ParseState *pstate, Node *parseTree) break; } + if (nodeTag(parseTree) != T_SelectStmt) + { + result->isPivot = false; + result->pivotInfoList = NIL; + } /* Mark as original query until we learn differently */ result->querySource = QSRC_ORIGINAL; result->canSetTag = true; @@ -1450,9 +1467,12 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) /* make WINDOW info available for window functions, too */ pstate->p_windowdefs = stmt->windowClause; + qry->isPivot = false; + qry->pivotInfoList = NIL; + if (stmt->isPivot && transform_pivot_clause_hook) { - (*transform_pivot_clause_hook)(pstate, stmt); + (*transform_pivot_clause_hook)(qry, pstate, stmt); } /* process the FROM clause */ diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 940b628be89..a0d32426b6a 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -3102,6 +3102,8 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, nothing_qry->rtable = pstate->p_rtable; nothing_qry->rteperminfos = pstate->p_rteperminfos; nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */ + nothing_qry->isPivot = false; + nothing_qry->pivotInfoList = NIL; *actions = list_make1(nothing_qry); } diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index d6325f7e6f4..e7cf42e20e4 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -48,6 +48,9 @@ bbfViewHasInsteadofTrigger_hook_type bbfViewHasInsteadofTrigger_hook = NULL; /** BBF Hook to check Instead Of trigger on View */ +/* Hooks for restoring PIVOT info from previously created view */ +rewrite_pivot_view_hook_type rewrite_pivot_view_hook = NULL; + /* We use a list of these to detect recursion in RewriteQuery */ typedef struct rewrite_event { @@ -1826,6 +1829,16 @@ ApplyRetrieveRule(Query *parsetree, */ rule_action = copyObject(linitial(rule->actions)); + /* + * If action query is a pivot stmt, we save the pivot related info to + * tsql_outmost_context + */ + if (sql_dialect == SQL_DIALECT_TSQL && rule_action->isPivot && rewrite_pivot_view_hook) + { + /* save information to tsql_outmost_context */ + (*rewrite_pivot_view_hook)(rule_action); + } + AcquireRewriteLocks(rule_action, true, (rc != NULL)); /* diff --git a/src/backend/rewrite/rewriteSearchCycle.c b/src/backend/rewrite/rewriteSearchCycle.c index b7c8e06fa2d..71d7b6e0762 100644 --- a/src/backend/rewrite/rewriteSearchCycle.c +++ b/src/backend/rewrite/rewriteSearchCycle.c @@ -279,6 +279,8 @@ rewriteSearchAndCycle(CommonTableExpr *cte) newq1 = makeNode(Query); newq1->commandType = CMD_SELECT; newq1->canSetTag = true; + newq1->isPivot = false; + newq1->pivotInfoList = NIL; newrte = makeNode(RangeTblEntry); newrte->rtekind = RTE_SUBQUERY; @@ -366,6 +368,8 @@ rewriteSearchAndCycle(CommonTableExpr *cte) newq2 = makeNode(Query); newq2->commandType = CMD_SELECT; newq2->canSetTag = true; + newq2->isPivot = false; + newq2->pivotInfoList = NIL; newrte = makeNode(RangeTblEntry); newrte->rtekind = RTE_SUBQUERY; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 8733e69be55..70aa7a2f60e 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -235,6 +235,9 @@ typedef struct Query int stmt_location; /* length in bytes; 0 means "rest of string" */ int stmt_len pg_node_attr(query_jumble_ignore); + + bool isPivot pg_node_attr(query_jumble_ignore); + List *pivotInfoList pg_node_attr(query_jumble_ignore); } Query; diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index 2a54e302fd4..e3c0d25fa24 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -65,7 +65,7 @@ typedef void (*pre_transform_setop_sort_clause_hook_type) (ParseState *pstate, Q extern PGDLLEXPORT pre_transform_setop_sort_clause_hook_type pre_transform_setop_sort_clause_hook; /* Hook for transform pivot clause in tsql select stmt */ -typedef void (*transform_pivot_clause_hook_type)(ParseState *pstate, SelectStmt *stmt); +typedef void (*transform_pivot_clause_hook_type)(Query *qry, ParseState *pstate, SelectStmt *stmt); extern PGDLLEXPORT transform_pivot_clause_hook_type transform_pivot_clause_hook; extern Query *parse_analyze_fixedparams(RawStmt *parseTree, const char *sourceText, diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index b71e20b087c..b2b8e312f66 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -32,4 +32,8 @@ extern int relation_is_updatable(Oid reloid, bool include_triggers, Bitmapset *include_cols); +/* Hooks for restoring PIVOT info from previously created view */ +typedef void (*rewrite_pivot_view_hook_type)(Query *qry); +extern PGDLLEXPORT rewrite_pivot_view_hook_type rewrite_pivot_view_hook; + #endif /* REWRITEHANDLER_H */ From e183412448b6ca299ed5170cfb41fc0dad10fbe4 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Wed, 20 Mar 2024 22:24:14 +0000 Subject: [PATCH 2/6] Add CTE/VIEW/JOIN support for PIVOT Modified internal PIVOT information analyzer -> executor passing design. Supported CTE/VIEW/JOIN as well as function/procedure for PIVOT operator. Task: BABEL-4713, BABEL-4714, BABEL-4673 Signed-off-by: Yanjie Xu --- src/backend/executor/execSRF.c | 7 +++++++ src/backend/executor/functions.c | 2 -- src/backend/nodes/makefuncs.c | 4 ++++ src/backend/optimizer/plan/planner.c | 6 +----- src/backend/optimizer/util/clauses.c | 6 ++++++ src/backend/parser/analyze.c | 22 +--------------------- src/backend/parser/parse_func.c | 11 +++++++++++ src/backend/parser/parse_utilcmd.c | 2 -- src/backend/rewrite/rewriteHandler.c | 13 ------------- src/backend/rewrite/rewriteSearchCycle.c | 4 ---- src/include/fmgr.h | 5 +++++ src/include/nodes/parsenodes.h | 5 ++--- src/include/nodes/primnodes.h | 4 ++++ src/include/parser/analyze.h | 2 +- src/include/rewrite/rewriteHandler.h | 4 ---- 15 files changed, 42 insertions(+), 55 deletions(-) diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index 73bf9152a4b..bbb36acb8de 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -25,6 +25,7 @@ #include "funcapi.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" +#include "parser/parser.h" #include "parser/parse_coerce.h" #include "pgstat.h" #include "utils/acl.h" @@ -203,6 +204,12 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); } + if (sql_dialect == SQL_DIALECT_TSQL && IsA(setexpr->expr, FuncExpr)) + { + fcinfo->pivot_parsetree = ((FuncExpr*) setexpr->expr)->pivot_parsetree; + fcinfo->pivot_extrainfo = ((FuncExpr*) setexpr->expr)->pivot_extrainfo; + } + /* * Switch to short-lived context for calling the function or expression. */ diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 1d457d45f13..f55424eb5ad 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -1936,8 +1936,6 @@ check_sql_fn_retval(List *queryTreeLists, newquery->querySource = parse->querySource; newquery->canSetTag = true; newquery->targetList = upper_tlist; - newquery->isPivot = false; - newquery->pivotInfoList = NIL; /* We need a moderately realistic colnames list for the subquery RTE */ colnames = NIL; diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 0e7e6e46d94..31a9ec5c44e 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -534,6 +534,8 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args, funcexpr->inputcollid = inputcollid; funcexpr->args = args; funcexpr->location = -1; + funcexpr->pivot_parsetree = NIL; + funcexpr->pivot_extrainfo = NIL; return funcexpr; } @@ -600,6 +602,8 @@ makeFuncCall(List *name, List *args, CoercionForm funcformat, int location) n->func_variadic = false; n->funcformat = funcformat; n->location = location; + n->pivot_parsetree = NIL; + n->pivot_extrainfo = NIL; return n; } diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 22794989baa..36cd8fbb238 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -6553,8 +6553,6 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) /* Set up mostly-dummy planner state */ query = makeNode(Query); query->commandType = CMD_SELECT; - query->isPivot = false; - query->pivotInfoList = NIL; glob = makeNode(PlannerGlobal); @@ -6677,9 +6675,7 @@ plan_create_index_workers(Oid tableOid, Oid indexOid) /* Set up largely-dummy planner state */ query = makeNode(Query); query->commandType = CMD_SELECT; - query->isPivot = false; - query->pivotInfoList = NIL; - + glob = makeNode(PlannerGlobal); root = makeNode(PlannerInfo); diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 840cafa27e8..39d68b234a0 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -2601,6 +2601,8 @@ eval_const_expressions_mutator(Node *node, newexpr->inputcollid = expr->inputcollid; newexpr->args = args; newexpr->location = expr->location; + newexpr->pivot_parsetree = expr->pivot_parsetree; + newexpr->pivot_extrainfo = expr->pivot_extrainfo; return (Node *) newexpr; } case T_OpExpr: @@ -4562,6 +4564,8 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, newexpr->inputcollid = input_collid; newexpr->args = args; newexpr->location = -1; + newexpr->pivot_parsetree = NIL; + newexpr->pivot_extrainfo = NIL; return evaluate_expr((Expr *) newexpr, result_type, result_typmod, result_collid); @@ -4674,6 +4678,8 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, fexpr->inputcollid = input_collid; fexpr->args = args; fexpr->location = -1; + fexpr->pivot_parsetree = NIL; + fexpr->pivot_extrainfo = NIL; /* Fetch the function body */ tmp = SysCacheGetAttrNotNull(PROCOID, func_tuple, Anum_pg_proc_prosrc); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index e01c2f79804..39a62e0b75b 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -407,23 +407,11 @@ transformStmt(ParseState *pstate, Node *parseTree) SelectStmt *n = (SelectStmt *) parseTree; if (n->valuesLists) - { result = transformValuesClause(pstate, n); - result->isPivot = false; - result->pivotInfoList = NIL; - } - else if (n->op == SETOP_NONE) - { result = transformSelectStmt(pstate, n); - } else - { result = transformSetOperationStmt(pstate, n); - result->isPivot = false; - result->pivotInfoList = NIL; - } - } break; @@ -471,11 +459,6 @@ transformStmt(ParseState *pstate, Node *parseTree) break; } - if (nodeTag(parseTree) != T_SelectStmt) - { - result->isPivot = false; - result->pivotInfoList = NIL; - } /* Mark as original query until we learn differently */ result->querySource = QSRC_ORIGINAL; result->canSetTag = true; @@ -1467,12 +1450,9 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) /* make WINDOW info available for window functions, too */ pstate->p_windowdefs = stmt->windowClause; - qry->isPivot = false; - qry->pivotInfoList = NIL; - if (stmt->isPivot && transform_pivot_clause_hook) { - (*transform_pivot_clause_hook)(qry, pstate, stmt); + (*transform_pivot_clause_hook)(pstate, stmt); } /* process the FROM clause */ diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 35c3eba0182..833baa30c42 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -765,6 +765,17 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, /* funccollid and inputcollid will be set by parse_collate.c */ funcexpr->args = fargs; funcexpr->location = location; + if (fn != NULL) + { + funcexpr->pivot_parsetree = copyObject(fn->pivot_parsetree); + funcexpr->pivot_extrainfo = copyObject(fn->pivot_extrainfo); + } + else + { + funcexpr->pivot_parsetree = NIL; + funcexpr->pivot_extrainfo = NIL; + } + retval = (Node *) funcexpr; } diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index a0d32426b6a..940b628be89 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -3102,8 +3102,6 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, nothing_qry->rtable = pstate->p_rtable; nothing_qry->rteperminfos = pstate->p_rteperminfos; nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */ - nothing_qry->isPivot = false; - nothing_qry->pivotInfoList = NIL; *actions = list_make1(nothing_qry); } diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e7cf42e20e4..d6325f7e6f4 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -48,9 +48,6 @@ bbfViewHasInsteadofTrigger_hook_type bbfViewHasInsteadofTrigger_hook = NULL; /** BBF Hook to check Instead Of trigger on View */ -/* Hooks for restoring PIVOT info from previously created view */ -rewrite_pivot_view_hook_type rewrite_pivot_view_hook = NULL; - /* We use a list of these to detect recursion in RewriteQuery */ typedef struct rewrite_event { @@ -1829,16 +1826,6 @@ ApplyRetrieveRule(Query *parsetree, */ rule_action = copyObject(linitial(rule->actions)); - /* - * If action query is a pivot stmt, we save the pivot related info to - * tsql_outmost_context - */ - if (sql_dialect == SQL_DIALECT_TSQL && rule_action->isPivot && rewrite_pivot_view_hook) - { - /* save information to tsql_outmost_context */ - (*rewrite_pivot_view_hook)(rule_action); - } - AcquireRewriteLocks(rule_action, true, (rc != NULL)); /* diff --git a/src/backend/rewrite/rewriteSearchCycle.c b/src/backend/rewrite/rewriteSearchCycle.c index 71d7b6e0762..b7c8e06fa2d 100644 --- a/src/backend/rewrite/rewriteSearchCycle.c +++ b/src/backend/rewrite/rewriteSearchCycle.c @@ -279,8 +279,6 @@ rewriteSearchAndCycle(CommonTableExpr *cte) newq1 = makeNode(Query); newq1->commandType = CMD_SELECT; newq1->canSetTag = true; - newq1->isPivot = false; - newq1->pivotInfoList = NIL; newrte = makeNode(RangeTblEntry); newrte->rtekind = RTE_SUBQUERY; @@ -368,8 +366,6 @@ rewriteSearchAndCycle(CommonTableExpr *cte) newq2 = makeNode(Query); newq2->commandType = CMD_SELECT; newq2->canSetTag = true; - newq2->isPivot = false; - newq2->pivotInfoList = NIL; newrte = makeNode(RangeTblEntry); newrte->rtekind = RTE_SUBQUERY; diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 5dc25803787..5814d000343 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -18,6 +18,7 @@ #ifndef FMGR_H #define FMGR_H +#include "nodes/pg_list.h" /* We don't want to include primnodes.h here, so make some stub references */ typedef struct Node *fmNodePtr; typedef struct Aggref *fmAggrefPtr; @@ -91,6 +92,8 @@ typedef struct FunctionCallInfoBaseData #define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4 bool isnull; /* function must set true if result is NULL */ short nargs; /* # arguments actually passed */ + List *pivot_parsetree; /* bbf_pivot function required rewritted parsetrees */ + List *pivot_extrainfo; /* bbf_pivot function required aggregation function and source sql string */ #define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6 NullableDatum args[FLEXIBLE_ARRAY_MEMBER]; } FunctionCallInfoBaseData; @@ -155,6 +158,8 @@ extern void fmgr_symbol(Oid functionId, char **mod, char **fn); (Fcinfo).fncollation = (Collation); \ (Fcinfo).isnull = false; \ (Fcinfo).nargs = (Nargs); \ + (Fcinfo).pivot_parsetree = NIL; \ + (Fcinfo).pivot_extrainfo = NIL; \ } while (0) /* diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 70aa7a2f60e..138eab8fb33 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -235,9 +235,6 @@ typedef struct Query int stmt_location; /* length in bytes; 0 means "rest of string" */ int stmt_len pg_node_attr(query_jumble_ignore); - - bool isPivot pg_node_attr(query_jumble_ignore); - List *pivotInfoList pg_node_attr(query_jumble_ignore); } Query; @@ -435,6 +432,8 @@ typedef struct FuncCall bool func_variadic; /* last argument was labeled VARIADIC */ CoercionForm funcformat; /* how to display this node */ int location; /* token location, or -1 if unknown */ + List *pivot_parsetree; /* bbf_pivot function required rewritted parsetrees */ + List *pivot_extrainfo; /* bbf_pivot function required aggregation function and source sql string */ } FuncCall; /* diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 55201447015..cc1132e3bb0 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -695,6 +695,10 @@ typedef struct FuncExpr List *args; /* token location, or -1 if unknown */ int location; + /* bbf_pivot function required rewritted parsetrees */ + List *pivot_parsetree pg_node_attr(query_jumble_ignore); + /* bbf_pivot function required aggregation function name and source sql string */ + List *pivot_extrainfo pg_node_attr(query_jumble_ignore); } FuncExpr; /* diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index e3c0d25fa24..2a54e302fd4 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -65,7 +65,7 @@ typedef void (*pre_transform_setop_sort_clause_hook_type) (ParseState *pstate, Q extern PGDLLEXPORT pre_transform_setop_sort_clause_hook_type pre_transform_setop_sort_clause_hook; /* Hook for transform pivot clause in tsql select stmt */ -typedef void (*transform_pivot_clause_hook_type)(Query *qry, ParseState *pstate, SelectStmt *stmt); +typedef void (*transform_pivot_clause_hook_type)(ParseState *pstate, SelectStmt *stmt); extern PGDLLEXPORT transform_pivot_clause_hook_type transform_pivot_clause_hook; extern Query *parse_analyze_fixedparams(RawStmt *parseTree, const char *sourceText, diff --git a/src/include/rewrite/rewriteHandler.h b/src/include/rewrite/rewriteHandler.h index b2b8e312f66..b71e20b087c 100644 --- a/src/include/rewrite/rewriteHandler.h +++ b/src/include/rewrite/rewriteHandler.h @@ -32,8 +32,4 @@ extern int relation_is_updatable(Oid reloid, bool include_triggers, Bitmapset *include_cols); -/* Hooks for restoring PIVOT info from previously created view */ -typedef void (*rewrite_pivot_view_hook_type)(Query *qry); -extern PGDLLEXPORT rewrite_pivot_view_hook_type rewrite_pivot_view_hook; - #endif /* REWRITEHANDLER_H */ From 67464747456821b32cab18bc393107f147452407 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Wed, 24 Apr 2024 21:41:19 +0000 Subject: [PATCH 3/6] [BABEL-4673] Disable CREATE VIEW ON stmt with PIVOT Disable CREATE VIEW ON stmt with PIVOT operator due to pg_dump cannot dump pivot view with correct dependency and newly added fields in FuncExpr casued readFunc failed to parse previous minor version string parsetree during select from view after mVU. Task: BABEL-4673 Signed-off-by: Yanjie Xu --- src/include/fmgr.h | 2 +- src/include/nodes/primnodes.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 5814d000343..f74e5cbb182 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -94,7 +94,7 @@ typedef struct FunctionCallInfoBaseData short nargs; /* # arguments actually passed */ List *pivot_parsetree; /* bbf_pivot function required rewritted parsetrees */ List *pivot_extrainfo; /* bbf_pivot function required aggregation function and source sql string */ -#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6 +#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 8 NullableDatum args[FLEXIBLE_ARRAY_MEMBER]; } FunctionCallInfoBaseData; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index cc1132e3bb0..b98457f9515 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -696,9 +696,9 @@ typedef struct FuncExpr /* token location, or -1 if unknown */ int location; /* bbf_pivot function required rewritted parsetrees */ - List *pivot_parsetree pg_node_attr(query_jumble_ignore); + List *pivot_parsetree pg_node_attr(query_jumble_ignore, read_write_ignore, read_as(NULL)); /* bbf_pivot function required aggregation function name and source sql string */ - List *pivot_extrainfo pg_node_attr(query_jumble_ignore); + List *pivot_extrainfo pg_node_attr(query_jumble_ignore, read_write_ignore, read_as(NULL)); } FuncExpr; /* From 3fd80cbd5b0fb40bb1c65c1aeb6c971c98d9428b Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Thu, 25 Apr 2024 15:42:56 +0000 Subject: [PATCH 4/6] [BABEL-4673] Remove newly added pivot fields in fcinfo Removed newly added pivot fields in fcinfo and set the fcinfo->context to pivot data when the FuncExpr is a bbf_pivot function Task: BABEL-4673 Signed-off-by: Yanjie Xu --- src/backend/executor/execSRF.c | 8 +++++--- src/include/fmgr.h | 6 +----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index bbb36acb8de..50b095aa866 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -204,10 +204,12 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); } - if (sql_dialect == SQL_DIALECT_TSQL && IsA(setexpr->expr, FuncExpr)) + /* if current FuncExpr is a bbf_pivot function, we set the fcinfo context to pivot data */ + if (sql_dialect == SQL_DIALECT_TSQL && IsA(setexpr->expr, FuncExpr) + && ((FuncExpr*) setexpr->expr)->pivot_parsetree != NIL + && ((FuncExpr*) setexpr->expr)->pivot_extrainfo != NIL) { - fcinfo->pivot_parsetree = ((FuncExpr*) setexpr->expr)->pivot_parsetree; - fcinfo->pivot_extrainfo = ((FuncExpr*) setexpr->expr)->pivot_extrainfo; + fcinfo->context = (Node *) list_make2(((FuncExpr*) setexpr->expr)->pivot_parsetree, ((FuncExpr*) setexpr->expr)->pivot_extrainfo); } /* diff --git a/src/include/fmgr.h b/src/include/fmgr.h index f74e5cbb182..1429cc1440c 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -92,9 +92,7 @@ typedef struct FunctionCallInfoBaseData #define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4 bool isnull; /* function must set true if result is NULL */ short nargs; /* # arguments actually passed */ - List *pivot_parsetree; /* bbf_pivot function required rewritted parsetrees */ - List *pivot_extrainfo; /* bbf_pivot function required aggregation function and source sql string */ -#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 8 +#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6 NullableDatum args[FLEXIBLE_ARRAY_MEMBER]; } FunctionCallInfoBaseData; @@ -158,8 +156,6 @@ extern void fmgr_symbol(Oid functionId, char **mod, char **fn); (Fcinfo).fncollation = (Collation); \ (Fcinfo).isnull = false; \ (Fcinfo).nargs = (Nargs); \ - (Fcinfo).pivot_parsetree = NIL; \ - (Fcinfo).pivot_extrainfo = NIL; \ } while (0) /* From 04adc9fc9f31740ec34b413b5e158b441d70f121 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Fri, 26 Apr 2024 07:40:25 +0000 Subject: [PATCH 5/6] [BABEL-4713] Clean up added fileds in FunCall/FuncExpr Replaced pivot related fields with generic Node * field in FuncCall and FuncExpr Task: BABEL-4713, BABEL-4714 Signed-off-by: Yanjie Xu --- src/backend/executor/execSRF.c | 13 ++++++++++--- src/backend/nodes/makefuncs.c | 6 ++---- src/backend/optimizer/util/clauses.c | 9 +++------ src/backend/parser/parse_func.c | 13 +++---------- src/include/nodes/parsenodes.h | 3 +-- src/include/nodes/primnodes.h | 6 ++---- 6 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index 50b095aa866..b7cdd1c351a 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -206,10 +206,17 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, /* if current FuncExpr is a bbf_pivot function, we set the fcinfo context to pivot data */ if (sql_dialect == SQL_DIALECT_TSQL && IsA(setexpr->expr, FuncExpr) - && ((FuncExpr*) setexpr->expr)->pivot_parsetree != NIL - && ((FuncExpr*) setexpr->expr)->pivot_extrainfo != NIL) + && ((FuncExpr*) setexpr->expr)->context != NULL + && (IsA(((FuncExpr*) setexpr->expr)->context, List))) { - fcinfo->context = (Node *) list_make2(((FuncExpr*) setexpr->expr)->pivot_parsetree, ((FuncExpr*) setexpr->expr)->pivot_extrainfo); + Node *node; + node = list_nth((List *)((FuncExpr*) setexpr->expr)->context, 0); + if (IsA(node, List) + && IsA(list_nth((List *)node, 0), String) + && strcmp(((String *)list_nth((List *)node, 0))->sval, "bbf_pivot_func") == 0) + { + fcinfo->context = ((FuncExpr*) setexpr->expr)->context; + } } /* diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 31a9ec5c44e..07af2177879 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -534,8 +534,7 @@ makeFuncExpr(Oid funcid, Oid rettype, List *args, funcexpr->inputcollid = inputcollid; funcexpr->args = args; funcexpr->location = -1; - funcexpr->pivot_parsetree = NIL; - funcexpr->pivot_extrainfo = NIL; + funcexpr->context = NULL; return funcexpr; } @@ -602,8 +601,7 @@ makeFuncCall(List *name, List *args, CoercionForm funcformat, int location) n->func_variadic = false; n->funcformat = funcformat; n->location = location; - n->pivot_parsetree = NIL; - n->pivot_extrainfo = NIL; + n->context = NULL; return n; } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 39d68b234a0..22ad68ab8f6 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -2601,8 +2601,7 @@ eval_const_expressions_mutator(Node *node, newexpr->inputcollid = expr->inputcollid; newexpr->args = args; newexpr->location = expr->location; - newexpr->pivot_parsetree = expr->pivot_parsetree; - newexpr->pivot_extrainfo = expr->pivot_extrainfo; + newexpr->context = expr->context; return (Node *) newexpr; } case T_OpExpr: @@ -4564,8 +4563,7 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, newexpr->inputcollid = input_collid; newexpr->args = args; newexpr->location = -1; - newexpr->pivot_parsetree = NIL; - newexpr->pivot_extrainfo = NIL; + newexpr->context = NULL; return evaluate_expr((Expr *) newexpr, result_type, result_typmod, result_collid); @@ -4678,8 +4676,7 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, fexpr->inputcollid = input_collid; fexpr->args = args; fexpr->location = -1; - fexpr->pivot_parsetree = NIL; - fexpr->pivot_extrainfo = NIL; + fexpr->context = NULL; /* Fetch the function body */ tmp = SysCacheGetAttrNotNull(PROCOID, func_tuple, Anum_pg_proc_prosrc); diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 833baa30c42..aa568514683 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -765,17 +765,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, /* funccollid and inputcollid will be set by parse_collate.c */ funcexpr->args = fargs; funcexpr->location = location; + funcexpr->context = NULL; + if (fn != NULL) - { - funcexpr->pivot_parsetree = copyObject(fn->pivot_parsetree); - funcexpr->pivot_extrainfo = copyObject(fn->pivot_extrainfo); - } - else - { - funcexpr->pivot_parsetree = NIL; - funcexpr->pivot_extrainfo = NIL; - } - + funcexpr->context = copyObject(fn->context); retval = (Node *) funcexpr; } diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 138eab8fb33..6e6d13cf2ec 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -432,8 +432,7 @@ typedef struct FuncCall bool func_variadic; /* last argument was labeled VARIADIC */ CoercionForm funcformat; /* how to display this node */ int location; /* token location, or -1 if unknown */ - List *pivot_parsetree; /* bbf_pivot function required rewritted parsetrees */ - List *pivot_extrainfo; /* bbf_pivot function required aggregation function and source sql string */ + Node *context; /* pass necessary info through planner and executor */ } FuncCall; /* diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index b98457f9515..b29f0c291ed 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -695,10 +695,8 @@ typedef struct FuncExpr List *args; /* token location, or -1 if unknown */ int location; - /* bbf_pivot function required rewritted parsetrees */ - List *pivot_parsetree pg_node_attr(query_jumble_ignore, read_write_ignore, read_as(NULL)); - /* bbf_pivot function required aggregation function name and source sql string */ - List *pivot_extrainfo pg_node_attr(query_jumble_ignore, read_write_ignore, read_as(NULL)); + /* pass necessary info through planner and executor */ + Node *context pg_node_attr(query_jumble_ignore, read_write_ignore, read_as(NULL)); } FuncExpr; /* From 4f0b415f0ab5fd3459a6e9e575c946d50418e9f4 Mon Sep 17 00:00:00 2001 From: Yanjie Xu Date: Fri, 26 Apr 2024 08:45:40 +0000 Subject: [PATCH 6/6] [BABEL-4713] Move code to Babelfish hook function Move executor pivot data passing code to Babelfish hook function. Task: BABEL-4713, BABEL-4714 Signed-off-by: Yanjie Xu --- src/backend/executor/execSRF.c | 18 +++++------------- src/backend/parser/analyze.c | 2 +- src/include/executor/executor.h | 2 ++ src/include/fmgr.h | 1 - 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/backend/executor/execSRF.c b/src/backend/executor/execSRF.c index b7cdd1c351a..b26b4ab7153 100644 --- a/src/backend/executor/execSRF.c +++ b/src/backend/executor/execSRF.c @@ -34,6 +34,8 @@ #include "utils/memutils.h" #include "utils/typcache.h" +/* Hook to set TSQL pivot data to fcinfo */ +pass_pivot_data_to_fcinfo_hook_type pass_pivot_data_to_fcinfo_hook = NULL; /* static function decls */ static void init_sexpr(Oid foid, Oid input_collation, Expr *node, @@ -203,20 +205,10 @@ ExecMakeTableFunctionResult(SetExprState *setexpr, /* Treat setexpr as a generic expression */ InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL); } - - /* if current FuncExpr is a bbf_pivot function, we set the fcinfo context to pivot data */ - if (sql_dialect == SQL_DIALECT_TSQL && IsA(setexpr->expr, FuncExpr) - && ((FuncExpr*) setexpr->expr)->context != NULL - && (IsA(((FuncExpr*) setexpr->expr)->context, List))) + + if (sql_dialect == SQL_DIALECT_TSQL && pass_pivot_data_to_fcinfo_hook) { - Node *node; - node = list_nth((List *)((FuncExpr*) setexpr->expr)->context, 0); - if (IsA(node, List) - && IsA(list_nth((List *)node, 0), String) - && strcmp(((String *)list_nth((List *)node, 0))->sval, "bbf_pivot_func") == 0) - { - fcinfo->context = ((FuncExpr*) setexpr->expr)->context; - } + (pass_pivot_data_to_fcinfo_hook)(fcinfo, setexpr->expr); } /* diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 39a62e0b75b..766b36deabc 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -89,7 +89,7 @@ pre_transform_setop_tree_hook_type pre_transform_setop_tree_hook = NULL; /* Hook to reset a query's targetlist after modification in pre_transfrom_sort_clause */ pre_transform_setop_sort_clause_hook_type pre_transform_setop_sort_clause_hook = NULL; -/* Hooks for transform TSQL pivot clause in select stmt */ +/* Hook to transform TSQL pivot clause in select stmt */ transform_pivot_clause_hook_type transform_pivot_clause_hook = NULL; static Query *transformOptionalSelectInto(ParseState *pstate, Node *parseTree); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 35ab4852cbd..0b3bdca7258 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -473,6 +473,8 @@ extern Datum ExecMakeFunctionResultSet(SetExprState *fcache, MemoryContext argContext, bool *isNull, ExprDoneCond *isDone); +typedef void (*pass_pivot_data_to_fcinfo_hook_type)(FunctionCallInfo fcinfo, Expr *expr); +extern PGDLLEXPORT pass_pivot_data_to_fcinfo_hook_type pass_pivot_data_to_fcinfo_hook; /* * prototypes from functions in execScan.c diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 1429cc1440c..5dc25803787 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -18,7 +18,6 @@ #ifndef FMGR_H #define FMGR_H -#include "nodes/pg_list.h" /* We don't want to include primnodes.h here, so make some stub references */ typedef struct Node *fmNodePtr; typedef struct Aggref *fmAggrefPtr;