From b44616044a4c96861e02440792044c7d1471845a Mon Sep 17 00:00:00 2001 From: Zhang Mingli Date: Thu, 13 Jun 2024 23:27:47 +0800 Subject: [PATCH] [AQUMV] Expose the function adjust view query and varno fix. Add new function aqumv_adjust_simple_query. Make it external for other codes may use the same logic. It has two main functions: Adjust view query, remove 'old' and 'new' rte for refresh, make it to be a valid query tree. Fix varno after that rewrite. Fix varnosyn, keep it with varno as we don't have syntactic one. Authored-by: Zhang Mingli avamingli@gmail.com --- src/backend/optimizer/plan/aqumv.c | 210 +++++++++++++++-------------- src/include/optimizer/aqumv.h | 26 ++++ 2 files changed, 135 insertions(+), 101 deletions(-) create mode 100644 src/include/optimizer/aqumv.h diff --git a/src/backend/optimizer/plan/aqumv.c b/src/backend/optimizer/plan/aqumv.c index 104ac29b3eb..f92ac72849a 100644 --- a/src/backend/optimizer/plan/aqumv.c +++ b/src/backend/optimizer/plan/aqumv.c @@ -22,6 +22,7 @@ #include "catalog/pg_inherits.h" #include "catalog/pg_rewrite.h" #include "cdb/cdbllize.h" +#include "optimizer/aqumv.h" #include "optimizer/optimizer.h" #include "optimizer/planmain.h" #include "optimizer/planner.h" @@ -50,6 +51,7 @@ typedef struct int varno; } aqumv_adjust_varno_context; +extern void aqumv_adjust_simple_query(Query *viewQuery); static bool aqumv_process_from_quals(Node *query_quals, Node *mv_quals, List** post_quals); static void aqumv_adjust_varno(Query *parse, int delta); static Node *aqumv_adjust_varno_mutator(Node *node, aqumv_adjust_varno_context *context); @@ -92,7 +94,6 @@ answer_query_using_materialized_views(PlannerInfo *root, Query *parse = root->parse; /* Query of origin SQL. */ Query *viewQuery; /* Query of view. */ RelOptInfo *mv_final_rel = current_rel; /* Final rel after rewritten. */ - ListCell *lc; Node *jtnode; Node *mvjtnode; int varno; @@ -271,35 +272,8 @@ answer_query_using_materialized_views(PlannerInfo *root, subroot->tuple_fraction = root->tuple_fraction; subroot->limit_tuples = root->limit_tuples; - /* - * AQUMV - * We have to rewrite now before we do the real Equivalent - * Transformation 'rewrite'. - * Because actions sotored in rule is not a normal query tree, - * it can't be used directly, ex: new/old realtions used to - * refresh mv. - * Earse unused relatoins, keep the right one. - */ - foreach(lc, viewQuery->rtable) - { - RangeTblEntry* rtetmp = lfirst(lc); - if ((rtetmp->relkind == RELKIND_MATVIEW) && - (rtetmp->alias != NULL) && - (strcmp(rtetmp->alias->aliasname, "new") == 0 || - strcmp(rtetmp->alias->aliasname,"old") == 0)) - { - foreach_delete_current(viewQuery->rtable, lc); - } - } - - /* - * Now we have the right relation, adjust - * varnos in its query tree. - * AQUMV_FIXME_MVP: Only one single relation - * is supported now, we could assign varno - * to 1 opportunistically. - */ - aqumv_adjust_varno(viewQuery, 1); + /* Adjust to valid query tree and fix varno after rewrite.*/ + aqumv_adjust_simple_query(viewQuery); /* * AQUMV_FIXME_MVP @@ -505,77 +479,6 @@ aqumv_init_context(List *view_tlist, TupleDesc mv_tupledesc) return context; } -/* - * Process varno after we eliminate mv's actions("old" and "new" relation) - * Correct rindex and all varnos with a delta. - * - * MV's actions query tree: - * [rtable] - * RangeTblEntry [rtekind=RTE_RELATION] - * [alias] Alias [aliasname="old"] - * RangeTblEntry [rtekind=RTE_RELATION] - * [alias] Alias [aliasname="new"] - * RangeTblEntry [rtekind=RTE_RELATION] - * [jointree] - * FromExpr [] - * [fromlist] - * RangeTblRef [rtindex=3] - * [targetList] - * TargetEntry [resno=1 resname="c1"] - * Var [varno=3 varattno=1] - * TargetEntry [resno=2 resname="c2"] - * Var [varno=3 varattno=2] - *------------------------------------------------------------------------------------------ - * MV's query tree after rewrite: - * [rtable] - * RangeTblEntry [rtekind=RTE_RELATION] - * [jointree] - * FromExpr [] - * [fromlist] - * RangeTblRef [rtindex=3] - * [targetList] - * TargetEntry [resno=1 resname="c1"] - * Var [varno=3 varattno=1] - * TargetEntry [resno=2 resname="c2"] - * Var [varno=3 varattno=2] - *------------------------------------------------------------------------------------------ - * MV's query tree after varno adjust: - * [rtable] - * RangeTblEntry [rtekind=RTE_RELATION] - * [jointree] - * FromExpr [] - * [fromlist] - * RangeTblRef [rtindex=1] - * [targetList] - * TargetEntry [resno=1 resname="c1"] - * Var [varno=1 varattno=1] - * TargetEntry [resno=2 resname="c2"] - * Var [varno=1 varattno=2] - * - */ -static void -aqumv_adjust_varno(Query* parse, int varno) -{ - aqumv_adjust_varno_context context; - context.varno = varno; - parse = query_tree_mutator(parse, aqumv_adjust_varno_mutator, &context, QTW_DONT_COPY_QUERY); -} - -/* - * Adjust varno and rindex with delta. - */ -static Node *aqumv_adjust_varno_mutator(Node *node, aqumv_adjust_varno_context *context) -{ - if (node == NULL) - return NULL; - if (IsA(node, Var)) - ((Var *)node)->varno = context->varno; - else if (IsA(node, RangeTblRef)) - /* AQUMV_FIXME_MVP: currently we have only one relation */ - ((RangeTblRef*) node)->rtindex = context->varno; - return expression_tree_mutator(node, aqumv_adjust_varno_mutator, context); -} - /* * Compute a node complexity recursively. * Complexity of a node is the total times we enter walker function after all @@ -811,3 +714,108 @@ aqumv_process_targetlist(aqumv_equivalent_transformation_context *context, List return !context->has_unmatched; } + +void aqumv_adjust_simple_query(Query *viewQuery) +{ + ListCell *lc; + /* + * AQUMV + * We have to rewrite now before we do the real Equivalent + * Transformation 'rewrite'. + * Because actions sotored in rule is not a normal query tree, + * it can't be used directly, ex: new/old realtions used to + * refresh mv. + * Earse unused relatoins, keep the right one. + */ + foreach (lc, viewQuery->rtable) + { + RangeTblEntry *rtetmp = lfirst(lc); + if ((rtetmp->relkind == RELKIND_MATVIEW) && + (rtetmp->alias != NULL) && + (strcmp(rtetmp->alias->aliasname, "new") == 0 || + strcmp(rtetmp->alias->aliasname, "old") == 0)) + { + foreach_delete_current(viewQuery->rtable, lc); + } + } + + /* + * Now we have the right relation, adjust + * varnos in its query tree. + * AQUMV_FIXME_MVP: Only one single relation + * is supported now, we could assign varno + * to 1 opportunistically. + */ + aqumv_adjust_varno(viewQuery, 1); +} + +/* + * Process varno after we eliminate mv's actions("old" and "new" relation) + * Correct rindex and all varnos with a delta. + * + * MV's actions query tree: + * [rtable] + * RangeTblEntry [rtekind=RTE_RELATION] + * [alias] Alias [aliasname="old"] + * RangeTblEntry [rtekind=RTE_RELATION] + * [alias] Alias [aliasname="new"] + * RangeTblEntry [rtekind=RTE_RELATION] + * [jointree] + * FromExpr [] + * [fromlist] + * RangeTblRef [rtindex=3] + * [targetList] + * TargetEntry [resno=1 resname="c1"] + * Var [varno=3 varattno=1] + * TargetEntry [resno=2 resname="c2"] + * Var [varno=3 varattno=2] + *------------------------------------------------------------------------------------------ + * MV's query tree after rewrite: + * [rtable] + * RangeTblEntry [rtekind=RTE_RELATION] + * [jointree] + * FromExpr [] + * [fromlist] + * RangeTblRef [rtindex=3] + * [targetList] + * TargetEntry [resno=1 resname="c1"] + * Var [varno=3 varattno=1] + * TargetEntry [resno=2 resname="c2"] + * Var [varno=3 varattno=2] + *------------------------------------------------------------------------------------------ + * MV's query tree after varno adjust: + * [rtable] + * RangeTblEntry [rtekind=RTE_RELATION] + * [jointree] + * FromExpr [] + * [fromlist] + * RangeTblRef [rtindex=1] + * [targetList] + * TargetEntry [resno=1 resname="c1"] + * Var [varno=1 varattno=1] + * TargetEntry [resno=2 resname="c2"] + * Var [varno=1 varattno=2] + * + */ +static void +aqumv_adjust_varno(Query* parse, int varno) +{ + aqumv_adjust_varno_context context; + context.varno = varno; + parse = query_tree_mutator(parse, aqumv_adjust_varno_mutator, &context, QTW_DONT_COPY_QUERY); +} + +static Node *aqumv_adjust_varno_mutator(Node *node, aqumv_adjust_varno_context *context) +{ + if (node == NULL) + return NULL; + if (IsA(node, Var)) + { + ((Var *)node)->varno = context->varno; + ((Var *)node)->varnosyn = context->varno; /* Keep syntactic with varno. */ + } + else if (IsA(node, RangeTblRef)) + /* AQUMV_FIXME_MVP: currently we have only one relation */ + ((RangeTblRef*) node)->rtindex = context->varno; + return expression_tree_mutator(node, aqumv_adjust_varno_mutator, context); +} diff --git a/src/include/optimizer/aqumv.h b/src/include/optimizer/aqumv.h new file mode 100644 index 00000000000..3aff8d6865e --- /dev/null +++ b/src/include/optimizer/aqumv.h @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- + * + * aqumv.h + * prototypes for optimizer/plan/aqumv.c. + * + * Portions Copyright (c) 2024, HashData Technology Limited. + * + * Author: Zhang Mingli + * + * src/include/optimizer/aqumv.h + * + *------------------------------------------------------------------------- + */ +#ifndef AQUMV_H +#define AQUMV_H + +#include "nodes/parsenodes.h" + +/* + * Adjust parse tree storaged in view's actions. + * Query should be a simple query, ex: + * select from a single table. + */ +extern void aqumv_adjust_simple_query(Query *viewQuery); + +#endif /* AQUMV_H */