Fix to get view definition string with correct column names (#26)
Previously, a query string returned from pg_ivm_get_querydef did not include column names specified when IMMV was defined by create_immv. This caused failures in maintenance of MIN/MAX aggregate views whose columns had alias names. It is fixed by rewriting the result column name in the parse tree using the view's tuple descriptor prior to calling pg_get_querydef for PG15 or higher, or specifying the tuple descriptor to get_query_def for PG14 or earlier.
This commit is contained in:
parent
79d4b13ba1
commit
4c6016999d
5 changed files with 81 additions and 45 deletions
|
|
@ -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,8 +391,8 @@ 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__
|
||||
---+-----+-----+-------------------+-------------------+---------------
|
||||
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
|
||||
|
|
@ -407,8 +407,8 @@ 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__
|
||||
---+-----+-----+-------------------+-------------------+---------------
|
||||
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
|
||||
|
|
@ -418,8 +418,8 @@ SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
|||
|
||||
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__
|
||||
---+-----+-----+-------------------+-------------------+---------------
|
||||
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
|
||||
|
|
@ -430,37 +430,37 @@ SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
|||
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__
|
||||
-----+-----+-------------------+-------------------+---------------
|
||||
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__
|
||||
-----+-----+-------------------+-------------------+---------------
|
||||
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__
|
||||
-----+-----+-------------------+-------------------+---------------
|
||||
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__
|
||||
-----+-----+-------------------+-------------------+---------------
|
||||
min_j | max_j | __ivm_count_min_j__ | __ivm_count_max_j__ | __ivm_count__
|
||||
-------+-------+---------------------+---------------------+---------------
|
||||
| | 0 | 0 | 0
|
||||
(1 row)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
3
pg_ivm.h
3
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
|
||||
|
|
|
|||
44
ruleutils.c
44
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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue