-- -- Testing insert on columnar tables. -- CREATE SCHEMA columnar_insert; SET search_path TO columnar_insert; CREATE TABLE test_insert_command (a int) USING columnar; -- test single row inserts fail select count(*) from test_insert_command; count --------------------------------------------------------------------- 0 (1 row) insert into test_insert_command values(1); select count(*) from test_insert_command; count --------------------------------------------------------------------- 1 (1 row) insert into test_insert_command default values; select count(*) from test_insert_command; count --------------------------------------------------------------------- 2 (1 row) -- test inserting from another table succeed CREATE TABLE test_insert_command_data (a int); select count(*) from test_insert_command_data; count --------------------------------------------------------------------- 0 (1 row) insert into test_insert_command_data values(1); select count(*) from test_insert_command_data; count --------------------------------------------------------------------- 1 (1 row) insert into test_insert_command select * from test_insert_command_data; select count(*) from test_insert_command; count --------------------------------------------------------------------- 3 (1 row) select version_major, version_minor, reserved_stripe_id, reserved_row_number from columnar_test_helpers.columnar_storage_info('test_insert_command'); version_major | version_minor | reserved_stripe_id | reserved_row_number --------------------------------------------------------------------- 2 | 0 | 4 | 450001 (1 row) SELECT * FROM columnar_test_helpers.chunk_group_consistency; consistent --------------------------------------------------------------------- t (1 row) drop table test_insert_command_data; drop table test_insert_command; -- test long attribute value insertion -- create sufficiently long text so that data is stored in toast CREATE TABLE test_long_text AS SELECT a as int_val, string_agg(random()::text, '') as text_val FROM generate_series(1, 10) a, generate_series(1, 1000) b GROUP BY a ORDER BY a; -- store hash values of text for later comparison CREATE TABLE test_long_text_hash AS SELECT int_val, md5(text_val) AS hash FROM test_long_text; CREATE TABLE test_columnar_long_text(int_val int, text_val text) USING columnar; -- store long text in columnar table INSERT INTO test_columnar_long_text SELECT * FROM test_long_text; SELECT * FROM columnar_test_helpers.chunk_group_consistency; consistent --------------------------------------------------------------------- t (1 row) -- drop source table to remove original text from toast DROP TABLE test_long_text; -- check if text data is still available in columnar table -- by comparing previously stored hash. SELECT a.int_val FROM test_long_text_hash a, test_columnar_long_text c WHERE a.int_val = c.int_val AND a.hash = md5(c.text_val); int_val --------------------------------------------------------------------- 1 2 3 4 5 6 7 8 9 10 (10 rows) DROP TABLE test_long_text_hash; DROP TABLE test_columnar_long_text; CREATE TABLE test_logical_replication(i int) USING columnar; -- should succeed INSERT INTO test_logical_replication VALUES (1); CREATE PUBLICATION test_columnar_publication FOR TABLE test_logical_replication; -- should fail; columnar does not support logical replication INSERT INTO test_logical_replication VALUES (2); ERROR: cannot insert into columnar table that is a part of a publication DROP PUBLICATION test_columnar_publication; -- should succeed INSERT INTO test_logical_replication VALUES (3); DROP TABLE test_logical_replication; -- -- test toast interactions -- -- row table with data in different storage formats CREATE TABLE test_toast_row(plain TEXT, main TEXT, external TEXT, extended TEXT); ALTER TABLE test_toast_row ALTER COLUMN plain SET STORAGE plain; -- inline, uncompressed ALTER TABLE test_toast_row ALTER COLUMN main SET STORAGE main; -- inline, compressed ALTER TABLE test_toast_row ALTER COLUMN external SET STORAGE external; -- out-of-line, uncompressed ALTER TABLE test_toast_row ALTER COLUMN extended SET STORAGE extended; -- out-of-line, compressed INSERT INTO test_toast_row VALUES( repeat('w', 5000), repeat('x', 5000), repeat('y', 5000), repeat('z', 5000)); SELECT pg_column_size(plain), pg_column_size(main), pg_column_size(external), pg_column_size(extended) FROM test_toast_row; pg_column_size | pg_column_size | pg_column_size | pg_column_size --------------------------------------------------------------------- 5004 | 69 | 5000 | 65 (1 row) CREATE TABLE test_toast_columnar(plain TEXT, main TEXT, external TEXT, extended TEXT) USING columnar; INSERT INTO test_toast_columnar SELECT plain, main, external, extended FROM test_toast_row; SELECT pg_column_size(plain), pg_column_size(main), pg_column_size(external), pg_column_size(extended) FROM test_toast_columnar; pg_column_size | pg_column_size | pg_column_size | pg_column_size --------------------------------------------------------------------- 5004 | 5004 | 5004 | 5004 (1 row) select version_major, version_minor, reserved_stripe_id, reserved_row_number from columnar_test_helpers.columnar_storage_info('test_toast_columnar'); version_major | version_minor | reserved_stripe_id | reserved_row_number --------------------------------------------------------------------- 2 | 0 | 2 | 150001 (1 row) SELECT * FROM columnar_test_helpers.chunk_group_consistency; consistent --------------------------------------------------------------------- t (1 row) DROP TABLE test_toast_row; DROP TABLE test_toast_columnar; -- Verify metadata for zero column tables. -- We support writing into zero column tables, but not reading from them. -- We test that metadata makes sense so we can fix the read path in future. CREATE TABLE zero_col() USING columnar; SELECT alter_columnar_table_set('zero_col', chunk_group_row_limit => 1000); alter_columnar_table_set --------------------------------------------------------------------- (1 row) INSERT INTO zero_col DEFAULT VALUES; INSERT INTO zero_col DEFAULT VALUES; INSERT INTO zero_col DEFAULT VALUES; INSERT INTO zero_col DEFAULT VALUES; CREATE TABLE zero_col_heap(); INSERT INTO zero_col_heap DEFAULT VALUES; INSERT INTO zero_col_heap DEFAULT VALUES; INSERT INTO zero_col_heap DEFAULT VALUES; INSERT INTO zero_col_heap DEFAULT VALUES; INSERT INTO zero_col_heap SELECT * FROM zero_col_heap; INSERT INTO zero_col_heap SELECT * FROM zero_col_heap; INSERT INTO zero_col_heap SELECT * FROM zero_col_heap; INSERT INTO zero_col_heap SELECT * FROM zero_col_heap; INSERT INTO zero_col SELECT * FROM zero_col_heap; select version_major, version_minor, reserved_stripe_id, reserved_row_number from columnar_test_helpers.columnar_storage_info('zero_col'); version_major | version_minor | reserved_stripe_id | reserved_row_number --------------------------------------------------------------------- 2 | 0 | 6 | 750001 (1 row) SELECT relname, stripe_num, chunk_group_count, row_count FROM columnar.stripe a, pg_class b WHERE columnar_test_helpers.columnar_relation_storageid(b.oid)=a.storage_id AND relname = 'zero_col' ORDER BY 1,2,3,4; relname | stripe_num | chunk_group_count | row_count --------------------------------------------------------------------- zero_col | 1 | 1 | 1 zero_col | 2 | 1 | 1 zero_col | 3 | 1 | 1 zero_col | 4 | 1 | 1 zero_col | 5 | 1 | 64 (5 rows) SELECT relname, stripe_num, value_count FROM columnar.chunk a, pg_class b WHERE columnar_test_helpers.columnar_relation_storageid(b.oid)=a.storage_id AND relname = 'zero_col' ORDER BY 1,2,3; relname | stripe_num | value_count --------------------------------------------------------------------- (0 rows) SELECT relname, stripe_num, chunk_group_num, row_count FROM columnar.chunk_group a, pg_class b WHERE columnar_test_helpers.columnar_relation_storageid(b.oid)=a.storage_id AND relname = 'zero_col' ORDER BY 1,2,3,4; relname | stripe_num | chunk_group_num | row_count --------------------------------------------------------------------- zero_col | 1 | 0 | 1 zero_col | 2 | 0 | 1 zero_col | 3 | 0 | 1 zero_col | 4 | 0 | 1 zero_col | 5 | 0 | 64 (5 rows) CREATE TABLE selfinsert(x int) USING columnar; SELECT alter_columnar_table_set('selfinsert', stripe_row_limit => 1000); alter_columnar_table_set --------------------------------------------------------------------- (1 row) BEGIN; INSERT INTO selfinsert SELECT generate_series(1,1010); INSERT INTO selfinsert SELECT * FROM selfinsert; SELECT SUM(x)=1021110 FROM selfinsert; ?column? --------------------------------------------------------------------- t (1 row) ROLLBACK; BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; INSERT INTO selfinsert SELECT generate_series(1,1010); INSERT INTO selfinsert SELECT * FROM selfinsert; SELECT SUM(x)=1021110 FROM selfinsert; ?column? --------------------------------------------------------------------- t (1 row) ROLLBACK; INSERT INTO selfinsert SELECT generate_series(1,1010); INSERT INTO selfinsert SELECT * FROM selfinsert; SELECT SUM(x)=1021110 FROM selfinsert; ?column? --------------------------------------------------------------------- t (1 row) CREATE TABLE selfconflict (f1 int PRIMARY KEY, f2 int) USING columnar; BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; INSERT INTO selfconflict VALUES (2,1), (2,2); ERROR: duplicate key value violates unique constraint "selfconflict_pkey" DETAIL: Key (f1)=(2) already exists. COMMIT; SELECT COUNT(*)=0 FROM selfconflict; ?column? --------------------------------------------------------------------- t (1 row) CREATE TABLE flush_create_index(a int, b int) USING columnar; BEGIN; INSERT INTO flush_create_index VALUES (5, 10); SET enable_seqscan TO OFF; SET columnar.enable_custom_scan TO OFF; SET enable_indexscan TO ON; CREATE INDEX ON flush_create_index(a); SELECT a FROM flush_create_index WHERE a=5; a --------------------------------------------------------------------- 5 (1 row) ROLLBACK; CREATE OR REPLACE FUNCTION test_columnar_storage_write_new_page(relation regclass) RETURNS void STRICT LANGUAGE c AS 'citus', 'test_columnar_storage_write_new_page'; CREATE TABLE aborted_write (a int, b int) USING columnar; SELECT test_columnar_storage_write_new_page('aborted_write'); test_columnar_storage_write_new_page --------------------------------------------------------------------- (1 row) SET client_min_messages TO DEBUG4; INSERT INTO aborted_write VALUES (5); DEBUG: Flushing Stripe of size 1 DEBUG: overwriting page 2 DETAIL: This can happen after a roll-back. RESET search_path; SET client_min_messages TO WARNING; DROP SCHEMA columnar_insert CASCADE;