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;
|
ROLLBACK;
|
||||||
-- support MIN(), MAX() aggregate functions
|
-- support MIN(), MAX() aggregate functions
|
||||||
BEGIN;
|
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"
|
NOTICE: created index "mv_ivm_min_max_index" on immv "mv_ivm_min_max"
|
||||||
create_immv
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
|
|
@ -391,8 +391,8 @@ NOTICE: created index "mv_ivm_min_max_index" on immv "mv_ivm_min_max"
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
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
|
1 | 10 | 10 | 1 | 1 | 1
|
||||||
2 | 20 | 20 | 1 | 1 | 1
|
2 | 20 | 20 | 1 | 1 | 1
|
||||||
3 | 30 | 30 | 1 | 1 | 1
|
3 | 30 | 30 | 1 | 1 | 1
|
||||||
|
|
@ -407,8 +407,8 @@ INSERT INTO mv_base_a VALUES
|
||||||
(4,41), (4,42),
|
(4,41), (4,42),
|
||||||
(5,51), (5,52);
|
(5,51), (5,52);
|
||||||
SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
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
|
1 | 10 | 12 | 3 | 3 | 3
|
||||||
2 | 20 | 22 | 3 | 3 | 3
|
2 | 20 | 22 | 3 | 3 | 3
|
||||||
3 | 30 | 32 | 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));
|
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;
|
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
|
1 | 11 | 12 | 2 | 2 | 2
|
||||||
2 | 20 | 22 | 2 | 2 | 2
|
2 | 20 | 22 | 2 | 2 | 2
|
||||||
3 | 30 | 31 | 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;
|
ROLLBACK;
|
||||||
-- support MIN(), MAX() aggregate functions without GROUP clause
|
-- support MIN(), MAX() aggregate functions without GROUP clause
|
||||||
BEGIN;
|
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
|
create_immv
|
||||||
-------------
|
-------------
|
||||||
1
|
1
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT * FROM mv_ivm_min_max;
|
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
|
10 | 50 | 5 | 5 | 5
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(0,0), (6,60), (7,70);
|
(0,0), (6,60), (7,70);
|
||||||
SELECT * FROM mv_ivm_min_max;
|
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
|
0 | 70 | 8 | 8 | 8
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
|
DELETE FROM mv_base_a WHERE (i,j) IN ((0,0), (7,70));
|
||||||
SELECT * FROM mv_ivm_min_max;
|
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
|
10 | 60 | 6 | 6 | 6
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DELETE FROM mv_base_a;
|
DELETE FROM mv_base_a;
|
||||||
SELECT * FROM mv_ivm_min_max;
|
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
|
| | 0 | 0 | 0
|
||||||
(1 row)
|
(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 refresh_by_heap_swap(Oid matviewOid, Oid OIDNewHeap, char relpersistence);
|
||||||
static void OpenImmvIncrementalMaintenance(void);
|
static void OpenImmvIncrementalMaintenance(void);
|
||||||
static void CloseImmvIncrementalMaintenance(void);
|
static void CloseImmvIncrementalMaintenance(void);
|
||||||
static Query *get_immv_query(Relation matviewRel);
|
|
||||||
|
|
||||||
static Query *rewrite_query_for_preupdate_state(Query *query, List *tables,
|
static Query *rewrite_query_for_preupdate_state(Query *query, List *tables,
|
||||||
TransactionId xid, CommandId cid,
|
TransactionId xid, CommandId cid,
|
||||||
|
|
@ -586,7 +585,7 @@ CloseImmvIncrementalMaintenance(void)
|
||||||
/*
|
/*
|
||||||
* get_immv_query - get the Query of IMMV.
|
* get_immv_query - get the Query of IMMV.
|
||||||
*/
|
*/
|
||||||
static Query *
|
Query *
|
||||||
get_immv_query(Relation matviewRel)
|
get_immv_query(Relation matviewRel)
|
||||||
{
|
{
|
||||||
Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock);
|
Relation pgIvmImmv = table_open(PgIvmImmvRelationId(), AccessShareLock);
|
||||||
|
|
@ -2559,7 +2558,7 @@ get_plan_for_recalc(Relation matviewRel, List *namelist, List *keys, Oid *keyTyp
|
||||||
char *viewdef;
|
char *viewdef;
|
||||||
|
|
||||||
/* get view definition of matview */
|
/* 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
|
* 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,
|
extern ObjectAddress ExecRefreshImmv(const RangeVar *relation, bool skipData,
|
||||||
const char *queryString, QueryCompletion *qc);
|
const char *queryString, QueryCompletion *qc);
|
||||||
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
extern bool ImmvIncrementalMaintenanceIsEnabled(void);
|
||||||
|
extern Query *get_immv_query(Relation matviewRel);
|
||||||
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
extern Datum IVM_immediate_before(PG_FUNCTION_ARGS);
|
||||||
extern Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS);
|
extern Datum IVM_immediate_maintenance(PG_FUNCTION_ARGS);
|
||||||
extern void AtAbort_IVM(void);
|
extern void AtAbort_IVM(void);
|
||||||
|
|
@ -53,6 +54,6 @@ extern bool isIvmName(const char *s);
|
||||||
|
|
||||||
/* ruleutils.c */
|
/* ruleutils.c */
|
||||||
|
|
||||||
extern char *pg_ivm_get_querydef(Query *query, bool pretty);
|
extern char *pg_ivm_get_viewdef(Relation immvrel, bool pretty);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
44
ruleutils.c
44
ruleutils.c
|
|
@ -15,6 +15,7 @@
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 150000)
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 150000)
|
||||||
|
#include "utils/rel.h"
|
||||||
#include "utils/ruleutils.h"
|
#include "utils/ruleutils.h"
|
||||||
#elif defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
#elif defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
||||||
#include "ruleutils_14.c"
|
#include "ruleutils_14.c"
|
||||||
|
|
@ -30,19 +31,49 @@
|
||||||
: PRETTYFLAG_INDENT)
|
: 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 pretty flags are determined by GET_PRETTY_FLAGS(pretty).
|
||||||
*
|
*
|
||||||
* The result is a palloc'd C string.
|
* The result is a palloc'd C string.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
char *
|
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)
|
#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);
|
return pg_get_querydef(query, pretty);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
int prettyFlags;
|
int prettyFlags;
|
||||||
|
|
@ -51,7 +82,12 @@ pg_ivm_get_querydef(Query *query, bool pretty)
|
||||||
|
|
||||||
initStringInfo(&buf);
|
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);
|
prettyFlags, WRAP_COLUMN_DEFAULT, 0);
|
||||||
|
|
||||||
return buf.data;
|
return buf.data;
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support MIN(), MAX() aggregate functions
|
-- support MIN(), MAX() aggregate functions
|
||||||
BEGIN;
|
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;
|
SELECT * FROM mv_ivm_min_max ORDER BY 1,2,3;
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(1,11), (1,12),
|
(1,11), (1,12),
|
||||||
|
|
@ -139,7 +139,7 @@ ROLLBACK;
|
||||||
|
|
||||||
-- support MIN(), MAX() aggregate functions without GROUP clause
|
-- support MIN(), MAX() aggregate functions without GROUP clause
|
||||||
BEGIN;
|
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;
|
SELECT * FROM mv_ivm_min_max;
|
||||||
INSERT INTO mv_base_a VALUES
|
INSERT INTO mv_base_a VALUES
|
||||||
(0,0), (6,60), (7,70);
|
(0,0), (6,60), (7,70);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue