diff --git a/expected/pg_ivm.out b/expected/pg_ivm.out index 3e74c52..1d33a4b 100644 --- a/expected/pg_ivm.out +++ b/expected/pg_ivm.out @@ -383,7 +383,7 @@ SELECT * FROM mv_ivm_avg_bug ORDER BY 1,2,3; ROLLBACK; -- support MIN(), MAX() aggregate functions BEGIN; -SELECT create_immv('mv_ivm_min_max', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i'); +SELECT create_immv('mv_ivm_min_max(i, min_j, max_j)', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i'); NOTICE: created index "mv_ivm_min_max_index" on immv "mv_ivm_min_max" create_immv ------------- @@ -391,13 +391,13 @@ NOTICE: created index "mv_ivm_min_max_index" on immv "mv_ivm_min_max" (1 row) SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3; - i | min | max | __ivm_count_min__ | __ivm_count_max__ | __ivm_count__ ----+-----+-----+-------------------+-------------------+--------------- - 1 | 10 | 10 | 1 | 1 | 1 - 2 | 20 | 20 | 1 | 1 | 1 - 3 | 30 | 30 | 1 | 1 | 1 - 4 | 40 | 40 | 1 | 1 | 1 - 5 | 50 | 50 | 1 | 1 | 1 + i | min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__ +---+-------+-------+---------------------+---------------------+--------------- + 1 | 10 | 10 | 1 | 1 | 1 + 2 | 20 | 20 | 1 | 1 | 1 + 3 | 30 | 30 | 1 | 1 | 1 + 4 | 40 | 40 | 1 | 1 | 1 + 5 | 50 | 50 | 1 | 1 | 1 (5 rows) INSERT INTO mv_base_a VALUES @@ -407,61 +407,61 @@ INSERT INTO mv_base_a VALUES (4,41), (4,42), (5,51), (5,52); SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3; - i | min | max | __ivm_count_min__ | __ivm_count_max__ | __ivm_count__ ----+-----+-----+-------------------+-------------------+--------------- - 1 | 10 | 12 | 3 | 3 | 3 - 2 | 20 | 22 | 3 | 3 | 3 - 3 | 30 | 32 | 3 | 3 | 3 - 4 | 40 | 42 | 3 | 3 | 3 - 5 | 50 | 52 | 3 | 3 | 3 + i | min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__ +---+-------+-------+---------------------+---------------------+--------------- + 1 | 10 | 12 | 3 | 3 | 3 + 2 | 20 | 22 | 3 | 3 | 3 + 3 | 30 | 32 | 3 | 3 | 3 + 4 | 40 | 42 | 3 | 3 | 3 + 5 | 50 | 52 | 3 | 3 | 3 (5 rows) DELETE FROM mv_base_a WHERE (i,j) IN ((1,10), (2,21), (3,32)); SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3; - i | min | max | __ivm_count_min__ | __ivm_count_max__ | __ivm_count__ ----+-----+-----+-------------------+-------------------+--------------- - 1 | 11 | 12 | 2 | 2 | 2 - 2 | 20 | 22 | 2 | 2 | 2 - 3 | 30 | 31 | 2 | 2 | 2 - 4 | 40 | 42 | 3 | 3 | 3 - 5 | 50 | 52 | 3 | 3 | 3 + i | min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__ +---+-------+-------+---------------------+---------------------+--------------- + 1 | 11 | 12 | 2 | 2 | 2 + 2 | 20 | 22 | 2 | 2 | 2 + 3 | 30 | 31 | 2 | 2 | 2 + 4 | 40 | 42 | 3 | 3 | 3 + 5 | 50 | 52 | 3 | 3 | 3 (5 rows) ROLLBACK; -- support MIN(), MAX() aggregate functions without GROUP clause BEGIN; -SELECT create_immv('mv_ivm_min_max', 'SELECT MIN(j), MAX(j) FROM mv_base_a'); +SELECT create_immv('mv_ivm_min_max(min_j, max_j)', 'SELECT MIN(j), MAX(j) FROM mv_base_a'); create_immv ------------- 1 (1 row) SELECT * FROM mv_ivm_min_max; - min | max | __ivm_count_min__ | __ivm_count_max__ | __ivm_count__ ------+-----+-------------------+-------------------+--------------- - 10 | 50 | 5 | 5 | 5 + min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__ +-------+-------+---------------------+---------------------+--------------- + 10 | 50 | 5 | 5 | 5 (1 row) INSERT INTO mv_base_a VALUES (0,0), (6,60), (7,70); SELECT * FROM mv_ivm_min_max; - min | max | __ivm_count_min__ | __ivm_count_max__ | __ivm_count__ ------+-----+-------------------+-------------------+--------------- - 0 | 70 | 8 | 8 | 8 + min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__ +-------+-------+---------------------+---------------------+--------------- + 0 | 70 | 8 | 8 | 8 (1 row) DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70)); SELECT * FROM mv_ivm_min_max; - min | max | __ivm_count_min__ | __ivm_count_max__ | __ivm_count__ ------+-----+-------------------+-------------------+--------------- - 10 | 60 | 6 | 6 | 6 + min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__ +-------+-------+---------------------+---------------------+--------------- + 10 | 60 | 6 | 6 | 6 (1 row) DELETE FROM mv_base_a; SELECT * FROM mv_ivm_min_max; - min | max | __ivm_count_min__ | __ivm_count_max__ | __ivm_count__ ------+-----+-------------------+-------------------+--------------- - | | 0 | 0 | 0 + min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__ +-------+-------+---------------------+---------------------+--------------- + | | 0 | 0 | 0 (1 row) ROLLBACK; diff --git a/matview.c b/matview.c index 19f4959..b5e715c 100644 --- a/matview.c +++ b/matview.c @@ -139,7 +139,6 @@ static uint64 refresh_immv_datafill(DestReceiver *dest, Query *query, static void refresh_by_heap_swap(Oid matviewOid, Oid OIDNewHeap, char relpersistence); static void OpenImmvIncrementalMaintenance(void); static void CloseImmvIncrementalMaintenance(void); -static Query *get_immv_query(Relation matviewRel); static Query *rewrite_query_for_preupdate_state(Query *query, List *tables, TransactionId xid, CommandId cid, @@ -586,7 +585,7 @@ CloseImmvIncrementalMaintenance(void) /* * get_immv_query - get the Query of IMMV. */ -static Query * +Query * get_immv_query(Relation matviewRel) { Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock); @@ -2559,7 +2558,7 @@ get_plan_for_recalc(Relation matviewRel, List *namelist, List *keys, Oid *keyTyp char *viewdef; /* get view definition of matview */ - viewdef = pg_ivm_get_querydef(get_immv_query(matviewRel), false); + viewdef = pg_ivm_get_viewdef(matviewRel, false); /* * Build a query string for recalculating values. This is like diff --git a/pg_ivm.h b/pg_ivm.h index 8648de6..25a8a26 100644 --- a/pg_ivm.h +++ b/pg_ivm.h @@ -46,6 +46,7 @@ extern void makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, extern ObjectAddress ExecRefreshImmv(const RangeVar *relation, bool skipData, const char *queryString, QueryCompletion *qc); extern bool ImmvIncrementalMaintenanceIsEnabled(void); +extern Query *get_immv_query(Relation matviewRel); extern Datum IVM_immediate_before(PG_FUNCTION_ARGS); extern Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS); extern void AtAbort_IVM(void); @@ -53,6 +54,6 @@ extern bool isIvmName(const char *s); /* ruleutils.c */ -extern char *pg_ivm_get_querydef(Query *query, bool pretty); +extern char *pg_ivm_get_viewdef(Relation immvrel, bool pretty); #endif diff --git a/ruleutils.c b/ruleutils.c index 70842e5..dfe1fe4 100644 --- a/ruleutils.c +++ b/ruleutils.c @@ -15,6 +15,7 @@ #include "postgres.h" #if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 150000) +#include "utils/rel.h" #include "utils/ruleutils.h" #elif defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000) #include "ruleutils_14.c" @@ -30,19 +31,49 @@ : PRETTYFLAG_INDENT) /* ---------- - * pg_get_querydef + * pg_ivm_get_viewdef * - * Public entry point to deparse one query parsetree. + * Public entry point to deparse a view definition query parsetree. * The pretty flags are determined by GET_PRETTY_FLAGS(pretty). * * The result is a palloc'd C string. * ---------- */ char * -pg_ivm_get_querydef(Query *query, bool pretty) +pg_ivm_get_viewdef(Relation immvrel, bool pretty) { + Query *query = get_immv_query(immvrel); + TupleDesc resultDesc = RelationGetDescr(immvrel); + #if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 150000) + ListCell *lc; + int colno = 0; + + /* + * Rewrite the result column name using the view's tuple + * descriptor. + * + * The column name is usually figured out in get_query_def + * using a tupleDesc specified as an argument, but this + * function is static, so we cannot directly call it. + * Therefore, we rewrite them prior to calling the public + * function pg_get_querydef (for PG15 or higher). + */ + query = copyObject(query); + foreach (lc, query->targetList) + { + TargetEntry *tle = (TargetEntry *) lfirst(lc); + + if (tle->resjunk) + continue; /* ignore junk entries */ + + colno++; + if (resultDesc && colno <= resultDesc->natts) + tle->resname = NameStr(TupleDescAttr(resultDesc, colno - 1)->attname); + } + return pg_get_querydef(query, pretty); + #else StringInfoData buf; int prettyFlags; @@ -51,7 +82,12 @@ pg_ivm_get_querydef(Query *query, bool pretty) initStringInfo(&buf); - get_query_def(query, &buf, NIL, NULL, true, + /* + * For PG14 or earlier, we use get_query_def which is copied + * from the core because any public function for this purpose + * is not available. + */ + get_query_def(query, &buf, NIL, resultDesc, true, prettyFlags, WRAP_COLUMN_DEFAULT, 0); return buf.data; diff --git a/sql/pg_ivm.sql b/sql/pg_ivm.sql index 7b585ad..1508612 100644 --- a/sql/pg_ivm.sql +++ b/sql/pg_ivm.sql @@ -124,7 +124,7 @@ ROLLBACK; -- support MIN(), MAX() aggregate functions BEGIN; -SELECT create_immv('mv_ivm_min_max', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i'); +SELECT create_immv('mv_ivm_min_max(i, min_j, max_j)', 'SELECT i, MIN(j), MAX(j) FROM mv_base_a GROUP BY i'); SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3; INSERT INTO mv_base_a VALUES (1,11), (1,12), @@ -139,7 +139,7 @@ ROLLBACK; -- support MIN(), MAX() aggregate functions without GROUP clause BEGIN; -SELECT create_immv('mv_ivm_min_max', 'SELECT MIN(j), MAX(j) FROM mv_base_a'); +SELECT create_immv('mv_ivm_min_max(min_j, max_j)', 'SELECT MIN(j), MAX(j) FROM mv_base_a'); SELECT * FROM mv_ivm_min_max; INSERT INTO mv_base_a VALUES (0,0), (6,60), (7,70);