Fix segfault in UNION queries with top-level ordering

We can't just filter the equivalence member based on em_is_child as our
hypertable might not be top-level equivalence member.
This commit is contained in:
Sven Klemm 2024-05-26 13:56:44 +02:00 committed by Sven Klemm
parent c4656f7604
commit 180c7be7bd
6 changed files with 96 additions and 12 deletions

1
.unreleased/pr_6957 Normal file
View File

@ -0,0 +1 @@
Fixes: #6957 Fix segfault in UNION queries with ordering on compressed chunks

View File

@ -195,7 +195,7 @@ build_compressed_scan_pathkeys(SortInfo *sort_info, PlannerInfo *root, List *chu
* already refers a compressed column, it is a bug. See
* build_sortinfo().
*/
Assert(compressed_em != NULL);
Ensure(compressed_em, "corresponding equivalence member not found");
required_compressed_pathkeys = lappend(required_compressed_pathkeys, pk);
@ -1482,17 +1482,6 @@ add_segmentby_to_equivalence_class(PlannerInfo *root, EquivalenceClass *cur_ec,
Var *var;
Assert(!bms_overlap(cur_em->em_relids, info->compressed_rel->relids));
/*
* We want to base our equivalence member on the hypertable equivalence
* member, not on the uncompressed chunk one, because the latter is
* marked as child itself. This is mostly relevant for PG16 where we
* have to specify a parent for the newly created equivalence member.
*/
if (cur_em->em_is_child)
{
continue;
}
/* only consider EquivalenceMembers that are Vars, possibly with RelabelType, of the
* uncompressed chunk */
var = (Var *) cur_em->em_expr;
@ -1501,6 +1490,13 @@ add_segmentby_to_equivalence_class(PlannerInfo *root, EquivalenceClass *cur_ec,
if (!(var && IsA(var, Var)))
continue;
/*
* We want to base our equivalence member on the hypertable equivalence
* member, not on the uncompressed chunk one. We can't just check for
* em_is_child though because the hypertable might be a child itself and not
* a top-level EquivalenceMember. This is mostly relevant for PG16+ where
* we have to specify a parent for the newly created equivalence member.
*/
if ((Index) var->varno != info->ht_rel->relid)
continue;

View File

@ -1040,3 +1040,27 @@ EXECUTE param_prep (1);
DEALLOCATE param_prep;
RESET plan_cache_mode;
-- test hypertable being non-toplevel equivalence member #6925
CREATE TABLE i6925_t1(observed timestamptz not null, queryid int8, total_exec_time int8);
CREATE TABLE i6925_t2(LIKE i6925_t1);
SELECT table_name FROM create_hypertable('i6925_t1', 'observed');
table_name
i6925_t1
(1 row)
ALTER TABLE i6925_t1 SET (timescaledb.compress, timescaledb.compress_segmentby = 'queryid');
NOTICE: default order by for hypertable "i6925_t1" is set to "observed DESC"
INSERT INTO i6925_t1 SELECT '2020-01-01', 1, 1;
SELECT count(compress_chunk(chunk_name)) FROM show_chunks('i6925_t1') chunk_name;
count
1
(1 row)
SELECT queryid, lag(total_exec_time) OVER (PARTITION BY queryid) FROM (SELECT * FROM i6925_t1 UNION ALL SELECT * FROM i6925_t2) q;
queryid | lag
---------+-----
1 |
(1 row)
DROP TABLE i6925_t1;
DROP TABLE i6925_t2;

View File

@ -1042,3 +1042,27 @@ EXECUTE param_prep (1);
DEALLOCATE param_prep;
RESET plan_cache_mode;
-- test hypertable being non-toplevel equivalence member #6925
CREATE TABLE i6925_t1(observed timestamptz not null, queryid int8, total_exec_time int8);
CREATE TABLE i6925_t2(LIKE i6925_t1);
SELECT table_name FROM create_hypertable('i6925_t1', 'observed');
table_name
i6925_t1
(1 row)
ALTER TABLE i6925_t1 SET (timescaledb.compress, timescaledb.compress_segmentby = 'queryid');
NOTICE: default order by for hypertable "i6925_t1" is set to "observed DESC"
INSERT INTO i6925_t1 SELECT '2020-01-01', 1, 1;
SELECT count(compress_chunk(chunk_name)) FROM show_chunks('i6925_t1') chunk_name;
count
1
(1 row)
SELECT queryid, lag(total_exec_time) OVER (PARTITION BY queryid) FROM (SELECT * FROM i6925_t1 UNION ALL SELECT * FROM i6925_t2) q;
queryid | lag
---------+-----
1 |
(1 row)
DROP TABLE i6925_t1;
DROP TABLE i6925_t2;

View File

@ -1042,3 +1042,27 @@ EXECUTE param_prep (1);
DEALLOCATE param_prep;
RESET plan_cache_mode;
-- test hypertable being non-toplevel equivalence member #6925
CREATE TABLE i6925_t1(observed timestamptz not null, queryid int8, total_exec_time int8);
CREATE TABLE i6925_t2(LIKE i6925_t1);
SELECT table_name FROM create_hypertable('i6925_t1', 'observed');
table_name
i6925_t1
(1 row)
ALTER TABLE i6925_t1 SET (timescaledb.compress, timescaledb.compress_segmentby = 'queryid');
NOTICE: default order by for hypertable "i6925_t1" is set to "observed DESC"
INSERT INTO i6925_t1 SELECT '2020-01-01', 1, 1;
SELECT count(compress_chunk(chunk_name)) FROM show_chunks('i6925_t1') chunk_name;
count
1
(1 row)
SELECT queryid, lag(total_exec_time) OVER (PARTITION BY queryid) FROM (SELECT * FROM i6925_t1 UNION ALL SELECT * FROM i6925_t2) q;
queryid | lag
---------+-----
1 |
(1 row)
DROP TABLE i6925_t1;
DROP TABLE i6925_t2;

View File

@ -331,3 +331,18 @@ EXECUTE param_prep (2);
EXECUTE param_prep (1);
DEALLOCATE param_prep;
RESET plan_cache_mode;
-- test hypertable being non-toplevel equivalence member #6925
CREATE TABLE i6925_t1(observed timestamptz not null, queryid int8, total_exec_time int8);
CREATE TABLE i6925_t2(LIKE i6925_t1);
SELECT table_name FROM create_hypertable('i6925_t1', 'observed');
ALTER TABLE i6925_t1 SET (timescaledb.compress, timescaledb.compress_segmentby = 'queryid');
INSERT INTO i6925_t1 SELECT '2020-01-01', 1, 1;
SELECT count(compress_chunk(chunk_name)) FROM show_chunks('i6925_t1') chunk_name;
SELECT queryid, lag(total_exec_time) OVER (PARTITION BY queryid) FROM (SELECT * FROM i6925_t1 UNION ALL SELECT * FROM i6925_t2) q;
DROP TABLE i6925_t1;
DROP TABLE i6925_t2;