Fix issue when copying into arrow slot

If you set the table access method for a hypertable all new chunks will
use `ArrowTupleTableSlot` but the copy code assumes that the parent
table has a virtual tuple table slot. This causes a crash when copying
a heap tuple since the values are stored in the "main" slot and not in
either of the child tuple table slots.

Fix this issue by storing the values in the uncompressed slot when it
is empty.
This commit is contained in:
Mats Kindahl 2024-09-09 10:39:02 +02:00 committed by Mats Kindahl
parent d28a9fc892
commit 1a9d319d4b
3 changed files with 84 additions and 0 deletions

View File

@ -732,6 +732,20 @@ tts_arrow_copy_heap_tuple(TupleTableSlot *slot)
copy_slot_values(slot, aslot->noncompressed_slot, slot->tts_tupleDescriptor->natts);
}
/* If the non-compressed slot is empty, we are being called as if we are a
* virtual TTS (from function `copyfrom` in src/copy.c), so in this case
* we should copy the heap tuple from the "root" slot, which is
* virtual.
*
* We already know that the "root" slot is not empty when this function is
* being called.
*
* This does an extra memcpy() of the tts_values and tts_isnull, so might
* be possible to optimize away.
*/
if (TTS_EMPTY(aslot->noncompressed_slot))
copy_slot_values(slot, aslot->noncompressed_slot, slot->tts_tupleDescriptor->natts);
/* Since this tuple is generated from a baserel, there are cases when PG
* code expects the TID (t_self) to be set (e.g., during ANALYZE). But
* this doesn't happen if the tuple is formed from values similar to a

View File

@ -105,6 +105,11 @@ select format('%I.%I', chunk_schema, chunk_name)::regclass as chunk2
where format('%I.%I', hypertable_schema, hypertable_name)::regclass = :'hypertable'::regclass
order by chunk2 asc
limit 1 offset 1 \gset
create view amrels as
select cl.oid::regclass as rel, am.amname, inh.inhparent::regclass as relparent
from pg_class cl
inner join pg_am am on (cl.relam = am.oid)
left join pg_inherits inh on (inh.inhrelid = cl.oid);
-- Compress the chunks and check that the counts are the same
select location_id, count(*) into orig from :hypertable GROUP BY location_id;
select compress_chunk(show_chunks(:'hypertable'), compress_using => 'hyperstore');
@ -209,3 +214,42 @@ select * from copy_test1 order by metric_id;
-- load it again, but this statement fails.
--
-- select * into subset from :hypertable where device_id between 0 and 10;
-- Testing copy into a table that has the access method set but has
-- already existing (compressed) heap-chunks in the table.
CREATE TABLE test1 (timec timestamptz , i integer, b bigint, t text);
SELECT table_name from create_hypertable('test1', 'timec');
NOTICE: adding not-null constraint to column "timec"
table_name
------------
test1
(1 row)
INSERT INTO test1 SELECT q, 10, 11, 'hello'
FROM generate_series( '2020-01-03 10:00:00-05', '2020-01-03 12:00:00-05' , '5 min'::interval) q;
alter table test1 set (timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = 'timec DESC');
SELECT compress_chunk(show_chunks('test1'));
compress_chunk
-----------------------------------------
_timescaledb_internal._hyper_5_15_chunk
(1 row)
select count(*) from test1;
count
-------
25
(1 row)
select * from amrels where relparent = 'test1'::regclass;
rel | amname | relparent
-----------------------------------------+--------+-----------
_timescaledb_internal._hyper_5_15_chunk | heap | test1
(1 row)
alter table test1 set access method hyperstore;
copy test1 from stdin delimiter ',';
select count(*) from test1;
count
-------
26
(1 row)

View File

@ -4,6 +4,12 @@
\ir include/setup_hyperstore.sql
create view amrels as
select cl.oid::regclass as rel, am.amname, inh.inhparent::regclass as relparent
from pg_class cl
inner join pg_am am on (cl.relam = am.oid)
left join pg_inherits inh on (inh.inhrelid = cl.oid);
-- Compress the chunks and check that the counts are the same
select location_id, count(*) into orig from :hypertable GROUP BY location_id;
select compress_chunk(show_chunks(:'hypertable'), compress_using => 'hyperstore');
@ -69,3 +75,23 @@ select * from copy_test1 order by metric_id;
--
-- select * into subset from :hypertable where device_id between 0 and 10;
-- Testing copy into a table that has the access method set but has
-- already existing (compressed) heap-chunks in the table.
CREATE TABLE test1 (timec timestamptz , i integer, b bigint, t text);
SELECT table_name from create_hypertable('test1', 'timec');
INSERT INTO test1 SELECT q, 10, 11, 'hello'
FROM generate_series( '2020-01-03 10:00:00-05', '2020-01-03 12:00:00-05' , '5 min'::interval) q;
alter table test1 set (timescaledb.compress_segmentby = 'b', timescaledb.compress_orderby = 'timec DESC');
SELECT compress_chunk(show_chunks('test1'));
select count(*) from test1;
select * from amrels where relparent = 'test1'::regclass;
alter table test1 set access method hyperstore;
copy test1 from stdin delimiter ',';
2020-01-02 11:16:00-05,11,16,copy
\.
select count(*) from test1;