Fix bugs of IVM that occur when column names are specified in aggregate views (#41)
The names of additional columns for aggregate views are derived from column names specified in the first parameter of create_immv, but when the number was less than the length of the actual target list, segmentation fault occurred. Furthermore, when the number of specified columns is more than the target list, it overrode additional column names and it caused a failure of incremental maintenance of an aggregate view. To fix then, check the length of the specified column name list not to access invalid area, and also prevent from overriding additional column names.
This commit is contained in:
parent
326720874e
commit
26f0b03b58
4 changed files with 81 additions and 3 deletions
14
createas.c
14
createas.c
|
|
@ -289,6 +289,15 @@ rewriteQueryForIMMV(Query *query, List *colNames)
|
|||
ParseState *pstate = make_parsestate(NULL);
|
||||
FuncCall *fn;
|
||||
|
||||
/*
|
||||
* Check the length of colunm name list not to override names of
|
||||
* additional columns
|
||||
*/
|
||||
if (list_length(colNames) > list_length(query->targetList))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("too many column names were specified")));
|
||||
|
||||
rewritten = copyObject(query);
|
||||
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
|
||||
|
||||
|
|
@ -321,10 +330,11 @@ rewriteQueryForIMMV(Query *query, List *colNames)
|
|||
foreach(lc, rewritten->targetList)
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
||||
char *resname = (colNames == NIL ? tle->resname : strVal(list_nth(colNames, tle->resno - 1)));
|
||||
char *resname = (colNames == NIL || foreach_current_index(lc) >= list_length(colNames) ?
|
||||
tle->resname : strVal(list_nth(colNames, tle->resno - 1)));
|
||||
|
||||
if (IsA(tle->expr, Aggref))
|
||||
makeIvmAggColumn(pstate, (Aggref *)tle->expr, resname, &next_resno, &aggs);
|
||||
makeIvmAggColumn(pstate, (Aggref *) tle->expr, resname, &next_resno, &aggs);
|
||||
}
|
||||
rewritten->targetList = list_concat(rewritten->targetList, aggs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -464,6 +464,55 @@ SELECT * FROM mv_ivm_min_max;
|
|||
| | 0 | 0 | 0
|
||||
(1 row)
|
||||
|
||||
ROLLBACK;
|
||||
-- aggregate views with column names specified
|
||||
BEGIN;
|
||||
SELECT create_immv('mv_ivm_agg(a)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
||||
create_immv
|
||||
-------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
||||
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
||||
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||
a | sum | __ivm_count_sum__ | __ivm_count__
|
||||
---+------+-------------------+---------------
|
||||
1 | 110 | 2 | 2
|
||||
2 | 2200 | 2 | 2
|
||||
3 | 300 | 1 | 1
|
||||
4 | 40 | 1 | 1
|
||||
5 | 50 | 1 | 1
|
||||
(5 rows)
|
||||
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
SELECT create_immv('mv_ivm_agg(a,b)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||
NOTICE: created index "mv_ivm_agg_index" on immv "mv_ivm_agg"
|
||||
create_immv
|
||||
-------------
|
||||
5
|
||||
(1 row)
|
||||
|
||||
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
||||
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
||||
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||
a | b | __ivm_count_b__ | __ivm_count__
|
||||
---+------+-----------------+---------------
|
||||
1 | 110 | 2 | 2
|
||||
2 | 2200 | 2 | 2
|
||||
3 | 300 | 1 | 1
|
||||
4 | 40 | 1 | 1
|
||||
5 | 50 | 1 | 1
|
||||
(5 rows)
|
||||
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
SELECT create_immv('mv_ivm_agg(a,b,c)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||
ERROR: too many column names were specified
|
||||
ROLLBACK;
|
||||
-- support self join view and multiple change on the same table
|
||||
BEGIN;
|
||||
|
|
|
|||
2
pg_ivm.c
2
pg_ivm.c
|
|
@ -224,7 +224,7 @@ create_immv(PG_FUNCTION_ARGS)
|
|||
query = transformStmt(pstate, (Node *)ctas);
|
||||
Assert(query->commandType == CMD_UTILITY && IsA(query->utilityStmt, CreateTableAsStmt));
|
||||
|
||||
ExecCreateImmv(pstate, (CreateTableAsStmt *)query->utilityStmt, NULL, NULL, &qc);
|
||||
ExecCreateImmv(pstate, (CreateTableAsStmt *) query->utilityStmt, NULL, NULL, &qc);
|
||||
|
||||
PG_RETURN_INT64(qc.nprocessed);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,25 @@ DELETE FROM mv_base_a;
|
|||
SELECT * FROM mv_ivm_min_max;
|
||||
ROLLBACK;
|
||||
|
||||
-- aggregate views with column names specified
|
||||
BEGIN;
|
||||
SELECT create_immv('mv_ivm_agg(a)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
||||
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
||||
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
SELECT create_immv('mv_ivm_agg(a,b)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||
INSERT INTO mv_base_a VALUES (1,100), (2,200), (3,300);
|
||||
UPDATE mv_base_a SET j = 2000 WHERE (i,j) = (2,20);
|
||||
DELETE FROM mv_base_a WHERE (i,j) = (3,30);
|
||||
SELECT * FROM mv_ivm_agg ORDER BY 1,2;
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
SELECT create_immv('mv_ivm_agg(a,b,c)', 'SELECT i, SUM(j) FROM mv_base_a GROUP BY i');
|
||||
ROLLBACK;
|
||||
|
||||
-- support self join view and multiple change on the same table
|
||||
BEGIN;
|
||||
CREATE TABLE base_t (i int, v int);
|
||||
|
|
|
|||
Loading…
Reference in a new issue