SHOW server_version \gset SELECT substring(:'server_version', '\d+')::int >= 14 AS server_version_ge_14 \gset \if :server_version_ge_14 \else \q \endif create schema pg14; set search_path to pg14; SET citus.shard_replication_factor TO 1; SET citus.next_shard_id TO 980000; SET citus.shard_count TO 2; -- test the new vacuum option, process_toast and also auto option for index_cleanup CREATE TABLE t1 (a int); SELECT create_distributed_table('t1','a'); create_distributed_table --------------------------------------------------------------------- (1 row) SET citus.log_remote_commands TO ON; VACUUM (FULL) t1; NOTICE: issuing VACUUM (FULL) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (FULL) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (FULL, PROCESS_TOAST) t1; NOTICE: issuing VACUUM (FULL,PROCESS_TOAST) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (FULL,PROCESS_TOAST) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (FULL, PROCESS_TOAST true) t1; NOTICE: issuing VACUUM (FULL,PROCESS_TOAST) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (FULL,PROCESS_TOAST) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (FULL, PROCESS_TOAST false) t1; ERROR: PROCESS_TOAST required with VACUUM FULL VACUUM (PROCESS_TOAST false) t1; NOTICE: issuing VACUUM pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (INDEX_CLEANUP AUTO) t1; NOTICE: issuing VACUUM (INDEX_CLEANUP auto) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (INDEX_CLEANUP auto) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (INDEX_CLEANUP) t1; NOTICE: issuing VACUUM (INDEX_CLEANUP auto) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (INDEX_CLEANUP auto) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (INDEX_CLEANUP AuTo) t1; NOTICE: issuing VACUUM (INDEX_CLEANUP auto) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (INDEX_CLEANUP auto) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (INDEX_CLEANUP false) t1; NOTICE: issuing VACUUM (INDEX_CLEANUP false) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (INDEX_CLEANUP false) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (INDEX_CLEANUP true) t1; NOTICE: issuing VACUUM (INDEX_CLEANUP true) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (INDEX_CLEANUP true) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (INDEX_CLEANUP "AUTOX") t1; ERROR: index_cleanup requires a Boolean value VACUUM (FULL, FREEZE, VERBOSE false, ANALYZE, SKIP_LOCKED, INDEX_CLEANUP, PROCESS_TOAST, TRUNCATE) t1; NOTICE: issuing VACUUM (ANALYZE,FREEZE,FULL,SKIP_LOCKED,PROCESS_TOAST,TRUNCATE,INDEX_CLEANUP auto) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (ANALYZE,FREEZE,FULL,SKIP_LOCKED,PROCESS_TOAST,TRUNCATE,INDEX_CLEANUP auto) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx VACUUM (FULL, FREEZE false, VERBOSE false, ANALYZE false, SKIP_LOCKED false, INDEX_CLEANUP "Auto", PROCESS_TOAST true, TRUNCATE false) t1; NOTICE: issuing VACUUM (FULL,PROCESS_TOAST,TRUNCATE false,INDEX_CLEANUP auto) pg14.t1_980000 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing VACUUM (FULL,PROCESS_TOAST,TRUNCATE false,INDEX_CLEANUP auto) pg14.t1_980001 DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx -- vacuum (process_toast true) should be vacuuming toast tables (default is true) CREATE TABLE local_vacuum_table(name text); select reltoastrelid from pg_class where relname='local_vacuum_table' \gset SELECT relfrozenxid AS frozenxid FROM pg_class WHERE oid=:reltoastrelid::regclass \gset VACUUM (FREEZE, PROCESS_TOAST true) local_vacuum_table; SELECT relfrozenxid::text::integer > :frozenxid AS frozen_performed FROM pg_class WHERE oid=:reltoastrelid::regclass; frozen_performed --------------------------------------------------------------------- t (1 row) -- vacuum (process_toast false) should not be vacuuming toast tables (default is true) SELECT relfrozenxid AS frozenxid FROM pg_class WHERE oid=:reltoastrelid::regclass \gset VACUUM (FREEZE, PROCESS_TOAST false) local_vacuum_table; SELECT relfrozenxid::text::integer = :frozenxid AS frozen_not_performed FROM pg_class WHERE oid=:reltoastrelid::regclass; frozen_not_performed --------------------------------------------------------------------- t (1 row) DROP TABLE local_vacuum_table; SET citus.log_remote_commands TO OFF; create table dist(a int, b int); select create_distributed_table('dist','a'); create_distributed_table --------------------------------------------------------------------- (1 row) create index idx on dist(a); set citus.log_remote_commands to on; -- make sure that we send the tablespace option SET citus.multi_shard_modify_mode TO 'sequential'; reindex(TABLESPACE test_tablespace) index idx; NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(TABLESPACE test_tablespace) index idx; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(TABLESPACE test_tablespace) index idx; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx reindex(TABLESPACE test_tablespace, verbose) index idx; INFO: index "idx" was reindexed NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(TABLESPACE test_tablespace, verbose) index idx; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(TABLESPACE test_tablespace, verbose) index idx; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (VERBOSE, TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (VERBOSE, TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx reindex(TABLESPACE test_tablespace, verbose false) index idx ; NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(TABLESPACE test_tablespace, verbose false) index idx ; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(TABLESPACE test_tablespace, verbose false) index idx ; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx reindex(verbose, TABLESPACE test_tablespace) index idx ; INFO: index "idx" was reindexed NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;SELECT assign_distributed_transaction_id(xx, xx, 'xxxxxxx'); DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET LOCAL search_path TO pg14; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(verbose, TABLESPACE test_tablespace) index idx ; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing reindex(verbose, TABLESPACE test_tablespace) index idx ; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (VERBOSE, TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing REINDEX (VERBOSE, TABLESPACE test_tablespace) INDEX pg14.xxxxx DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing PREPARE TRANSACTION 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing COMMIT PREPARED 'citus_xx_xx_xx_xx' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx -- should error saying table space doesn't exist reindex(TABLESPACE test_tablespace1) index idx; ERROR: tablespace "test_tablespace1" does not exist reset citus.log_remote_commands; -- CREATE STATISTICS only allow simple column references CREATE TABLE tbl1(a timestamp, b int); SELECT create_distributed_table('tbl1','a'); create_distributed_table --------------------------------------------------------------------- (1 row) -- the last one should error out CREATE STATISTICS s1 (dependencies) ON a, b FROM tbl1; CREATE STATISTICS s2 (mcv) ON a, b FROM tbl1; CREATE STATISTICS s3 (ndistinct) ON date_trunc('month', a), date_trunc('day', a) FROM tbl1; ERROR: only simple column references are allowed in CREATE STATISTICS set citus.log_remote_commands to off; -- error out in case of ALTER TABLE .. DETACH PARTITION .. CONCURRENTLY/FINALIZE -- only if it's a distributed partitioned table CREATE TABLE par (a INT UNIQUE) PARTITION BY RANGE(a); CREATE TABLE par_1 PARTITION OF par FOR VALUES FROM (1) TO (4); CREATE TABLE par_2 PARTITION OF par FOR VALUES FROM (5) TO (8); -- works as it's not distributed ALTER TABLE par DETACH PARTITION par_1 CONCURRENTLY; -- errors out SELECT create_distributed_table('par','a'); create_distributed_table --------------------------------------------------------------------- (1 row) ALTER TABLE par DETACH PARTITION par_2 CONCURRENTLY; ERROR: ALTER TABLE .. DETACH PARTITION .. CONCURRENTLY commands are currently unsupported. ALTER TABLE par DETACH PARTITION par_2 FINALIZE; ERROR: ALTER TABLE .. DETACH PARTITION .. FINALIZE commands are currently unsupported. -- test column compression propagation in distribution SET citus.shard_replication_factor TO 1; CREATE TABLE col_compression (a TEXT COMPRESSION pglz, b TEXT); SELECT create_distributed_table('col_compression', 'a', shard_count:=4); create_distributed_table --------------------------------------------------------------------- (1 row) SELECT attname || ' ' || attcompression::text AS column_compression FROM pg_attribute WHERE attrelid::regclass::text LIKE 'col\_compression%' AND attnum > 0 ORDER BY 1; column_compression --------------------------------------------------------------------- a p b (2 rows) SELECT result AS column_compression FROM run_command_on_workers($$SELECT ARRAY( SELECT attname || ' ' || attcompression::text FROM pg_attribute WHERE attrelid::regclass::text LIKE 'pg14.col\_compression%' AND attnum > 0 ORDER BY 1 )$$); column_compression --------------------------------------------------------------------- {"a p","a p","a p","b ","b ","b "} {"a p","a p","a p","b ","b ","b "} (2 rows) -- test column compression propagation in rebalance SELECT shardid INTO moving_shard FROM citus_shards WHERE table_name='col_compression'::regclass AND nodeport=:worker_1_port LIMIT 1; SELECT citus_move_shard_placement((SELECT * FROM moving_shard), :'public_worker_1_host', :worker_1_port, :'public_worker_2_host', :worker_2_port, shard_transfer_mode := 'block_writes'); citus_move_shard_placement --------------------------------------------------------------------- (1 row) SELECT rebalance_table_shards('col_compression', rebalance_strategy := 'by_shard_count', shard_transfer_mode := 'block_writes'); NOTICE: Moving shard xxxxx from localhost:xxxxx to localhost:xxxxx ... rebalance_table_shards --------------------------------------------------------------------- (1 row) SELECT public.wait_for_resource_cleanup(); wait_for_resource_cleanup --------------------------------------------------------------------- (1 row) SELECT result AS column_compression FROM run_command_on_workers($$SELECT ARRAY( SELECT attname || ' ' || attcompression::text FROM pg_attribute WHERE attrelid::regclass::text LIKE 'pg14.col\_compression%' AND attnum > 0 ORDER BY 1 )$$); column_compression --------------------------------------------------------------------- {"a p","a p","a p","b ","b ","b "} {"a p","a p","a p","b ","b ","b "} (2 rows) -- test propagation of ALTER TABLE .. ALTER COLUMN .. SET COMPRESSION .. ALTER TABLE col_compression ALTER COLUMN b SET COMPRESSION pglz; ALTER TABLE col_compression ALTER COLUMN a SET COMPRESSION default; SELECT result AS column_compression FROM run_command_on_workers($$SELECT ARRAY( SELECT attname || ' ' || attcompression::text FROM pg_attribute WHERE attrelid::regclass::text LIKE 'pg14.col\_compression%' AND attnum > 0 ORDER BY 1 )$$); column_compression --------------------------------------------------------------------- {"a ","a ","a ","b p","b p","b p"} {"a ","a ","a ","b p","b p","b p"} (2 rows) -- test propagation of ALTER TABLE .. ADD COLUMN .. COMPRESSION .. ALTER TABLE col_compression ADD COLUMN c TEXT COMPRESSION pglz; SELECT result AS column_compression FROM run_command_on_workers($$SELECT ARRAY( SELECT attname || ' ' || attcompression::text FROM pg_attribute WHERE attrelid::regclass::text LIKE 'pg14.col\_compression%' AND attnum > 0 ORDER BY 1 )$$); column_compression --------------------------------------------------------------------- {"a ","a ","a ","b p","b p","b p","c p","c p","c p"} {"a ","a ","a ","b p","b p","b p","c p","c p","c p"} (2 rows) -- test attaching to a partitioned table with column compression CREATE TABLE col_comp_par (a TEXT COMPRESSION pglz, b TEXT) PARTITION BY RANGE (a); SELECT create_distributed_table('col_comp_par', 'a'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE col_comp_par_1 PARTITION OF col_comp_par FOR VALUES FROM ('abc') TO ('def'); SELECT result AS column_compression FROM run_command_on_workers($$SELECT ARRAY( SELECT attname || ' ' || attcompression::text FROM pg_attribute WHERE attrelid::regclass::text LIKE 'pg14.col\_comp\_par\_1\_%' AND attnum > 0 ORDER BY 1 )$$); column_compression --------------------------------------------------------------------- {"a p","b "} {"a p","b "} (2 rows) RESET citus.multi_shard_modify_mode; -- test procedure OUT parameters with procedure pushdown CREATE TABLE prctbl(val int primary key); CREATE OR REPLACE PROCEDURE insert_data(arg1 integer) LANGUAGE PLPGSQL AS $$ BEGIN RAISE NOTICE 'Proc with no OUT args'; INSERT INTO pg14.prctbl VALUES (arg1); END; $$; CREATE PROCEDURE insert_data_out(val integer, OUT res text) LANGUAGE PLPGSQL AS $$ BEGIN RAISE NOTICE 'Proc with OUT args'; INSERT INTO pg14.prctbl VALUES (val); res := 'insert_data_out():proc-result'::text; END $$; CREATE FUNCTION insert_data_out_fn(val integer, OUT res text) RETURNS TEXT LANGUAGE PLPGSQL AS $$ BEGIN RAISE NOTICE 'Func with OUT args'; INSERT INTO pg14.prctbl VALUES (val); res := 'insert_data_out_fn():func-result'::text; END; $$; CREATE OR REPLACE PROCEDURE proc_varargs( IN inp INT, OUT total NUMERIC, OUT average NUMERIC, VARIADIC list NUMERIC[]) AS $$ BEGIN SELECT INTO total SUM(list[i]) FROM generate_subscripts(list, 1) g(i); SELECT INTO average AVG(list[i]) FROM generate_subscripts(list, 1) g(i); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE PROCEDURE proc_varargs_inout( IN inp INT, OUT total NUMERIC, OUT average NUMERIC, INOUT result TEXT, VARIADIC list NUMERIC[]) AS $$ BEGIN SELECT 'Final:' || result INTO result; SELECT INTO total SUM(list[i]) FROM generate_subscripts(list, 1) g(i); SELECT INTO average AVG(list[i]) FROM generate_subscripts(list, 1) g(i); END; $$ LANGUAGE plpgsql; -- Named arguments CREATE OR REPLACE PROCEDURE proc_namedargs( IN inp INT, OUT total NUMERIC, OUT average NUMERIC, INOUT result TEXT) AS $$ BEGIN RAISE NOTICE 'IN passed: %', inp; SELECT 'Final:' || result INTO result; total := 999; average := 99; END; $$ LANGUAGE plpgsql; -- Mix of IN, OUT, INOUT and Variadic CREATE OR REPLACE PROCEDURE proc_namedargs_var( IN inp1 INT, IN inp2 INT, INOUT inout1 TEXT, OUT out1 INT, VARIADIC list INT[]) AS $$ DECLARE sum INT; BEGIN out1 := 5; SELECT INTO sum SUM(list[i]) FROM generate_subscripts(list, 1) g(i); RAISE NOTICE 'Input-1: % Input-2: % VarSum: %', inp1, inp2, sum; SELECT 'Final : ' || inout1 INTO inout1; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE PROCEDURE proc_varargs_inout2( INOUT result TEXT, OUT total NUMERIC, OUT average NUMERIC, IN inp INT, VARIADIC list NUMERIC[]) AS $$ BEGIN RAISE NOTICE 'IN passed: %', inp; SELECT 'Final:' || result INTO result; SELECT INTO total SUM(list[i]) FROM generate_subscripts(list, 1) g(i); SELECT INTO average AVG(list[i]) FROM generate_subscripts(list, 1) g(i); END; $$ LANGUAGE plpgsql; CREATE OR REPLACE PROCEDURE proc_varargs_inout3( OUT total NUMERIC, OUT average NUMERIC, INOUT result TEXT, IN inp INT, VARIADIC list NUMERIC[]) AS $$ BEGIN RAISE NOTICE 'IN passed: %', inp; SELECT 'Final:' || result INTO result; SELECT INTO total SUM(list[i]) FROM generate_subscripts(list, 1) g(i); SELECT INTO average AVG(list[i]) FROM generate_subscripts(list, 1) g(i); END; $$ LANGUAGE plpgsql; -- Function overload CREATE PROCEDURE proc_namedargs_overload( IN inp INT) AS $$ BEGIN RAISE NOTICE 'IN passed INT: %', inp; END; $$ LANGUAGE plpgsql; CREATE PROCEDURE proc_namedargs_overload( IN inp NUMERIC) AS $$ BEGIN RAISE NOTICE 'IN passed NUMERIC: %', inp; END; $$ LANGUAGE plpgsql; -- Before distribution CALL insert_data(1); NOTICE: Proc with no OUT args CONTEXT: PL/pgSQL function insert_data(integer) line XX at RAISE CALL insert_data_out(2, 'whythisarg'); NOTICE: Proc with OUT args CONTEXT: PL/pgSQL function insert_data_out(integer) line XX at RAISE res --------------------------------------------------------------------- insert_data_out():proc-result (1 row) SELECT insert_data_out_fn(3); NOTICE: Func with OUT args CONTEXT: PL/pgSQL function insert_data_out_fn(integer) line XX at RAISE insert_data_out_fn --------------------------------------------------------------------- insert_data_out_fn():func-result (1 row) -- Return the average and the sum of 2, 8, 20 CALL proc_varargs(1, 1, 1, 2, 8, 20); total | average --------------------------------------------------------------------- 30 | 10.0000000000000000 (1 row) CALL proc_varargs_inout(1, 1, 1, 'Testing in/out/var arguments'::text, 2, 8, 20); total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:Testing in/out/var arguments (1 row) CALL proc_varargs_inout(2, 1, 1, to_char(99,'FM99'), 2, 8, 20); total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:99 (1 row) CALL proc_varargs_inout(3, 1, 1, TRIM( BOTH FROM ' TEST COERCE_SQL_SYNTAX '), 2, 8, 20); total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:TEST COERCE_SQL_SYNTAX (1 row) CALL proc_namedargs(total=>3, result=>'Named args'::text, average=>2::NUMERIC, inp=>4); NOTICE: IN passed: 4 CONTEXT: PL/pgSQL function proc_namedargs(integer,text) line XX at RAISE total | average | result --------------------------------------------------------------------- 999 | 99 | Final:Named args (1 row) CALL proc_namedargs_var(inout1=> 'INOUT third argument'::text, out1=>4, inp2=>2, inp1=>1, variadic list=>'{9, 9, 9}'); NOTICE: Input-1: 1 Input-2: 2 VarSum: 27 CONTEXT: PL/pgSQL function proc_namedargs_var(integer,integer,text,integer[]) line XX at RAISE inout1 | out1 --------------------------------------------------------------------- Final : INOUT third argument | 5 (1 row) CALL proc_varargs_inout2('In Out', 1, 1, 5, 2, 8, 20); NOTICE: IN passed: 5 CONTEXT: PL/pgSQL function proc_varargs_inout2(text,integer,numeric[]) line XX at RAISE result | total | average --------------------------------------------------------------------- Final:In Out | 30 | 10.0000000000000000 (1 row) CALL proc_varargs_inout3(1, 1, 'In Out', 6, 2, 8, 20); NOTICE: IN passed: 6 CONTEXT: PL/pgSQL function proc_varargs_inout3(text,integer,numeric[]) line XX at RAISE total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:In Out (1 row) CALL proc_namedargs_overload(3); NOTICE: IN passed INT: 3 CONTEXT: PL/pgSQL function proc_namedargs_overload(integer) line XX at RAISE CALL proc_namedargs_overload(4.0); NOTICE: IN passed NUMERIC: 4.0 CONTEXT: PL/pgSQL function proc_namedargs_overload(numeric) line XX at RAISE CALL proc_namedargs_overload(inp=>5); NOTICE: IN passed INT: 5 CONTEXT: PL/pgSQL function proc_namedargs_overload(integer) line XX at RAISE CALL proc_namedargs_overload(inp=>6.0); NOTICE: IN passed NUMERIC: 6.0 CONTEXT: PL/pgSQL function proc_namedargs_overload(numeric) line XX at RAISE -- Distribute the table, procedure and function SELECT create_distributed_table('prctbl', 'val', colocate_with := 'none'); NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg14.prctbl$$) create_distributed_table --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'insert_data(int)', 'arg1', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'insert_data_out(int)', 'val', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'insert_data_out_fn(int)', 'val', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_varargs(int, NUMERIC[])', 'inp', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_varargs_inout(int, text, NUMERIC[])', 'inp', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_namedargs(int, text)', 'inp', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_namedargs_var(int, int, text, int[])', 'inp1', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_varargs_inout2(text, int, NUMERIC[])', 'inp', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_varargs_inout3(text, int, NUMERIC[])', 'inp', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_namedargs_overload(int)', 'inp', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) SELECT create_distributed_function( 'proc_namedargs_overload(numeric)', 'inp', colocate_with := 'prctbl' ); create_distributed_function --------------------------------------------------------------------- (1 row) CREATE TABLE test_proc_table (a int); create or replace procedure proc_pushdown(dist_key integer, OUT created int4[], OUT res_out text) language plpgsql as $$ DECLARE res INT := 0; begin INSERT INTO pg14.test_proc_table VALUES (dist_key); SELECT count(*) INTO res FROM pg14.test_proc_table; created := created || res; PERFORM array_prepend(res, created); res_out := res::text; commit; end;$$; -- show the behaviour before distributing CALL proc_pushdown(1, NULL, NULL); created | res_out --------------------------------------------------------------------- {1} | 1 (1 row) CALL proc_pushdown(1, ARRAY[2000,1], 'AAAA'); created | res_out --------------------------------------------------------------------- {2} | 2 (1 row) -- make sure that metadata is synced SELECT bool_and(hasmetadata) FROM pg_dist_node WHERE nodeport IN (:worker_1_port, :worker_2_port); bool_and --------------------------------------------------------------------- t (1 row) SELECT create_distributed_table('test_proc_table', 'a'); NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg14.test_proc_table$$) create_distributed_table --------------------------------------------------------------------- (1 row) SELECT create_distributed_function('proc_pushdown(integer)', 'dist_key', 'test_proc_table' ); create_distributed_function --------------------------------------------------------------------- (1 row) -- pushdown procedures with OUT parameters SET client_min_messages TO DEBUG1; CALL proc_pushdown(1, NULL, NULL); DEBUG: pushing down the procedure created | res_out --------------------------------------------------------------------- {3} | 3 (1 row) CALL proc_pushdown(1, ARRAY[2000,1], 'AAAA'); DEBUG: pushing down the procedure created | res_out --------------------------------------------------------------------- {4} | 4 (1 row) CALL insert_data(4); DEBUG: pushing down the procedure NOTICE: Proc with no OUT args DETAIL: from localhost:xxxxx CALL insert_data_out(5, 'whythisarg'); DEBUG: pushing down the procedure NOTICE: Proc with OUT args DETAIL: from localhost:xxxxx res --------------------------------------------------------------------- insert_data_out():proc-result (1 row) SELECT insert_data_out_fn(6); DEBUG: pushing down the function call NOTICE: Func with OUT args DETAIL: from localhost:xxxxx insert_data_out_fn --------------------------------------------------------------------- insert_data_out_fn():func-result (1 row) -- Return the average and the sum of 2, 8, 20 CALL proc_varargs(1, 1, 1, 2, 8, 20); DEBUG: pushing down the procedure total | average --------------------------------------------------------------------- 30 | 10.0000000000000000 (1 row) CALL proc_varargs_inout(1, 1, 1, 'Testing in/out/var arguments'::text, 2, 8, 20); DEBUG: pushing down the procedure total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:Testing in/out/var arguments (1 row) CALL proc_varargs_inout(2, 1, 1, to_char(99,'FM99'), 2, 8, 20); DEBUG: pushing down the procedure total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:99 (1 row) CALL proc_varargs_inout(3, 1, 1, TRIM( BOTH FROM ' TEST COERCE_SQL_SYNTAX '), 2, 8, 20); DEBUG: pushing down the procedure total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:TEST COERCE_SQL_SYNTAX (1 row) CALL proc_namedargs(total=>3, result=>'Named args'::text, average=>2::NUMERIC, inp=>4); DEBUG: pushing down the procedure NOTICE: IN passed: 4 DETAIL: from localhost:xxxxx total | average | result --------------------------------------------------------------------- 999 | 99 | Final:Named args (1 row) CALL proc_namedargs_var(inout1=> 'INOUT third argument'::text, out1=>4, inp2=>2, inp1=>1, variadic list=>'{9, 9, 9}'); DEBUG: pushing down the procedure NOTICE: Input-1: 1 Input-2: 2 VarSum: 27 DETAIL: from localhost:xxxxx inout1 | out1 --------------------------------------------------------------------- Final : INOUT third argument | 5 (1 row) CALL proc_varargs_inout2('In Out', 1, 1, 5, 2, 8, 20); DEBUG: pushing down the procedure NOTICE: IN passed: 5 DETAIL: from localhost:xxxxx result | total | average --------------------------------------------------------------------- Final:In Out | 30 | 10.0000000000000000 (1 row) CALL proc_varargs_inout3(1, 1, 'In Out', 6, 2, 8, 20); DEBUG: pushing down the procedure NOTICE: IN passed: 6 DETAIL: from localhost:xxxxx total | average | result --------------------------------------------------------------------- 30 | 10.0000000000000000 | Final:In Out (1 row) CALL proc_namedargs_overload(3); DEBUG: pushing down the procedure NOTICE: IN passed INT: 3 DETAIL: from localhost:xxxxx CALL proc_namedargs_overload(4.0); DEBUG: pushing down the procedure NOTICE: IN passed NUMERIC: 4.0 DETAIL: from localhost:xxxxx CALL proc_namedargs_overload(inp=>5); DEBUG: pushing down the procedure NOTICE: IN passed INT: 5 DETAIL: from localhost:xxxxx CALL proc_namedargs_overload(inp=>6.0); DEBUG: pushing down the procedure NOTICE: IN passed NUMERIC: 6.0 DETAIL: from localhost:xxxxx RESET client_min_messages; -- ALTER STATISTICS .. OWNER TO CURRENT_ROLE CREATE TABLE st1 (a int, b int); CREATE STATISTICS role_s1 ON a, b FROM st1; SELECT create_distributed_table('st1','a'); create_distributed_table --------------------------------------------------------------------- (1 row) ALTER STATISTICS role_s1 OWNER TO CURRENT_ROLE; CREATE ROLE role_1 WITH LOGIN SUPERUSER; ALTER STATISTICS role_s1 OWNER TO CURRENT_ROLE; SELECT run_command_on_workers($$SELECT rolname FROM pg_roles WHERE oid IN (SELECT stxowner FROM pg_statistic_ext WHERE stxname LIKE 'role\_s1%');$$); run_command_on_workers --------------------------------------------------------------------- (localhost,57637,t,postgres) (localhost,57638,t,postgres) (2 rows) SET ROLE role_1; ALTER STATISTICS role_s1 OWNER TO CURRENT_ROLE; SELECT run_command_on_workers($$SELECT rolname FROM pg_roles WHERE oid IN (SELECT stxowner FROM pg_statistic_ext WHERE stxname LIKE 'role\_s1%');$$); run_command_on_workers --------------------------------------------------------------------- (localhost,57637,t,role_1) (localhost,57638,t,role_1) (2 rows) SET ROLE postgres; ALTER STATISTICS role_s1 OWNER TO CURRENT_USER; SELECT run_command_on_workers($$SELECT rolname FROM pg_roles WHERE oid IN (SELECT stxowner FROM pg_statistic_ext WHERE stxname LIKE 'role\_s1%');$$); run_command_on_workers --------------------------------------------------------------------- (localhost,57637,t,postgres) (localhost,57638,t,postgres) (2 rows) SET ROLE to NONE; ALTER STATISTICS role_s1 OWNER TO CURRENT_ROLE; SELECT run_command_on_workers($$SELECT rolname FROM pg_roles WHERE oid IN (SELECT stxowner FROM pg_statistic_ext WHERE stxname LIKE 'role\_s1%');$$); run_command_on_workers --------------------------------------------------------------------- (localhost,57637,t,postgres) (localhost,57638,t,postgres) (2 rows) create TABLE test_jsonb_subscript ( id int, test_json jsonb ); SELECT create_distributed_table('test_jsonb_subscript', 'id'); create_distributed_table --------------------------------------------------------------------- (1 row) insert into test_jsonb_subscript values (1, '{}'), -- empty jsonb (2, '{"key": "value"}'); -- jsonb with data -- update empty jsonb update test_jsonb_subscript set test_json['a'] = '1' where id = 1; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"a": 1} 2 | {"key": "value"} (2 rows) -- update jsonb with some data update test_jsonb_subscript set test_json['a'] = '1' where id = 2; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"a": 1} 2 | {"a": 1, "key": "value"} (2 rows) -- replace jsonb update test_jsonb_subscript set test_json['a'] = '"test"'; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"a": "test"} 2 | {"a": "test", "key": "value"} (2 rows) -- replace by object update test_jsonb_subscript set test_json['a'] = '{"b": 1}'::jsonb; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"a": {"b": 1}} 2 | {"a": {"b": 1}, "key": "value"} (2 rows) -- replace by array update test_jsonb_subscript set test_json['a'] = '[1, 2, 3]'::jsonb; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"a": [1, 2, 3]} 2 | {"a": [1, 2, 3], "key": "value"} (2 rows) -- use jsonb subscription in where clause select * from test_jsonb_subscript where test_json['key'] = '"value"' ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 2 | {"a": [1, 2, 3], "key": "value"} (1 row) select * from test_jsonb_subscript where test_json['key_doesnt_exists'] = '"value"' ORDER BY 1,2; id | test_json --------------------------------------------------------------------- (0 rows) select * from test_jsonb_subscript where test_json['key'] = '"wrong_value"' ORDER BY 1,2; id | test_json --------------------------------------------------------------------- (0 rows) -- NULL update test_jsonb_subscript set test_json[NULL] = '1'; ERROR: jsonb subscript in assignment must not be null CONTEXT: while executing command on localhost:xxxxx update test_jsonb_subscript set test_json['another_key'] = NULL; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"a": [1, 2, 3], "another_key": null} 2 | {"a": [1, 2, 3], "key": "value", "another_key": null} (2 rows) -- NULL as jsonb source insert into test_jsonb_subscript values (3, NULL); update test_jsonb_subscript set test_json['a'] = '1' where id = 3; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"a": [1, 2, 3], "another_key": null} 2 | {"a": [1, 2, 3], "key": "value", "another_key": null} 3 | {"a": 1} (3 rows) update test_jsonb_subscript set test_json = NULL where id = 3; update test_jsonb_subscript set test_json[0] = '1'; select * from test_jsonb_subscript ORDER BY 1,2; id | test_json --------------------------------------------------------------------- 1 | {"0": 1, "a": [1, 2, 3], "another_key": null} 2 | {"0": 1, "a": [1, 2, 3], "key": "value", "another_key": null} 3 | [1] (3 rows) -- JOIN ALIAS CREATE TABLE J1_TBL ( i integer, j integer, t text ); CREATE TABLE J2_TBL ( i integer, k integer ); INSERT INTO J1_TBL VALUES (1, 4, 'one'); INSERT INTO J1_TBL VALUES (2, 3, 'two'); INSERT INTO J1_TBL VALUES (3, 2, 'three'); INSERT INTO J1_TBL VALUES (4, 1, 'four'); INSERT INTO J1_TBL VALUES (5, 0, 'five'); INSERT INTO J1_TBL VALUES (6, 6, 'six'); INSERT INTO J1_TBL VALUES (7, 7, 'seven'); INSERT INTO J1_TBL VALUES (8, 8, 'eight'); INSERT INTO J1_TBL VALUES (0, NULL, 'zero'); INSERT INTO J2_TBL VALUES (1, -1); INSERT INTO J2_TBL VALUES (2, 2); INSERT INTO J2_TBL VALUES (3, -3); INSERT INTO J2_TBL VALUES (2, 4); INSERT INTO J2_TBL VALUES (5, -5); INSERT INTO J2_TBL VALUES (5, -5); INSERT INTO J2_TBL VALUES (0, NULL); SELECT create_distributed_table('J1_TBL','i'); NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg14.j1_tbl$$) create_distributed_table --------------------------------------------------------------------- (1 row) SELECT create_distributed_table('J2_TBL','i'); NOTICE: Copying data from local table... NOTICE: copying the data has completed DETAIL: The local data in the table is no longer visible, but is still on disk. HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$pg14.j2_tbl$$) create_distributed_table --------------------------------------------------------------------- (1 row) -- test join using aliases SELECT * FROM J1_TBL JOIN J2_TBL USING (i) WHERE J1_TBL.t = 'one' ORDER BY 1,2,3,4; -- ok i | j | t | k --------------------------------------------------------------------- 1 | 4 | one | -1 (1 row) SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one' ORDER BY 1,2,3,4; -- ok i | j | t | k --------------------------------------------------------------------- 1 | 4 | one | -1 (1 row) SELECT * FROM (J1_TBL JOIN J2_TBL USING (i)) AS x WHERE J1_TBL.t = 'one' ORDER BY 1,2,3,4; -- error ERROR: invalid reference to FROM-clause entry for table "j1_tbl" HINT: There is an entry for table "j1_tbl", but it cannot be referenced from this part of the query. SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE x.i = 1 ORDER BY 1,2,3,4; -- ok i | j | t | k --------------------------------------------------------------------- 1 | 4 | one | -1 (1 row) SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE x.t = 'one' ORDER BY 1,2,3,4; -- error ERROR: column x.t does not exist SELECT * FROM (J1_TBL JOIN J2_TBL USING (i) AS x) AS xx WHERE x.i = 1 ORDER BY 1,2,3,4; -- error (XXX could use better hint) ERROR: missing FROM-clause entry for table "x" SELECT * FROM J1_TBL a1 JOIN J2_TBL a2 USING (i) AS a1 ORDER BY 1,2,3,4; -- error ERROR: table name "a1" specified more than once SELECT x.* FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one' ORDER BY 1; i --------------------------------------------------------------------- 1 (1 row) SELECT ROW(x.*) FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one' ORDER BY 1; row --------------------------------------------------------------------- (1) (1 row) SELECT * FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE x.i > 1 ORDER BY 1,2,3,4; i | j | t | k --------------------------------------------------------------------- 2 | 3 | two | 2 2 | 3 | two | 4 3 | 2 | three | -3 5 | 0 | five | -5 5 | 0 | five | -5 (5 rows) -- ORDER BY is not supported for json and this returns 1 row, so it is okay. SELECT row_to_json(x.*) FROM J1_TBL JOIN J2_TBL USING (i) AS x WHERE J1_TBL.t = 'one'; row_to_json --------------------------------------------------------------------- {"f1":1} (1 row) -- we don't support REINDEX TABLE queries on distributed partitioned tables CREATE TABLE dist_part_table (a int) PARTITION BY RANGE (a); CREATE TABLE dist_part_table_1 PARTITION OF dist_part_table FOR VALUES FROM (1) TO (5); CREATE TABLE dist_part_table_2 PARTITION OF dist_part_table FOR VALUES FROM (5) TO (10); SELECT create_distributed_table('dist_part_table', 'a'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE INDEX dist_part_idx ON dist_part_table(a); REINDEX TABLE dist_part_table; ERROR: REINDEX TABLE queries on distributed partitioned tables are not supported -- but we support REINDEXing partitions REINDEX TABLE dist_part_table_1; -- test if we error with CTEs with search clauses CREATE TABLE graph0(f INT, t INT, label TEXT); SELECT create_distributed_table('graph0', 'f'); create_distributed_table --------------------------------------------------------------------- (1 row) INSERT INTO graph0 VALUES (1, 2, 'arc 1 -> 2'), (1, 3, 'arc 1 -> 3'), (2, 3, 'arc 2 -> 3'), (1, 4, 'arc 1 -> 4'), (4, 5, 'arc 4 -> 5'); WITH RECURSIVE search_graph(f, t, label) AS ( SELECT * FROM graph0 g WHERE f = 1 UNION ALL SELECT g.* FROM graph0 g, search_graph sg WHERE g.f = sg.t and g.f = 1 ) SEARCH DEPTH FIRST BY f, t SET seq SELECT * FROM search_graph ORDER BY seq; ERROR: recursive CTEs are not supported in distributed queries WITH RECURSIVE search_graph(f, t, label) AS ( SELECT * FROM graph0 g WHERE f = 1 UNION ALL SELECT g.* FROM graph0 g, search_graph sg WHERE g.f = sg.t and g.f = 1 ) SEARCH DEPTH FIRST BY f, t SET seq DELETE FROM graph0 WHERE t IN (SELECT t FROM search_graph ORDER BY seq); ERROR: recursive CTEs are not supported in distributed queries CREATE TABLE graph1(f INT, t INT, label TEXT); SELECT create_reference_table('graph1'); create_reference_table --------------------------------------------------------------------- (1 row) INSERT INTO graph1 VALUES (1, 2, 'arc 1 -> 2'), (1, 3, 'arc 1 -> 3'), (2, 3, 'arc 2 -> 3'), (1, 4, 'arc 1 -> 4'), (4, 5, 'arc 4 -> 5'); WITH RECURSIVE search_graph(f, t, label) AS ( SELECT * FROM graph1 g WHERE f = 1 UNION ALL SELECT g.* FROM graph1 g, search_graph sg WHERE g.f = sg.t and g.f = 1 ) SEARCH DEPTH FIRST BY f, t SET seq SELECT * FROM search_graph ORDER BY seq; ERROR: recursive CTEs are not supported in distributed queries WITH RECURSIVE search_graph(f, t, label) AS ( SELECT * FROM graph1 g WHERE f = 1 UNION ALL SELECT g.* FROM graph1 g, search_graph sg WHERE g.f = sg.t and g.f = 1 ) SEARCH DEPTH FIRST BY f, t SET seq DELETE FROM graph1 WHERE t IN (SELECT t FROM search_graph ORDER BY seq); ERROR: recursive CTEs are not supported in distributed queries SELECT * FROM ( WITH RECURSIVE search_graph(f, t, label) AS ( SELECT * FROM graph0 g WHERE f = 1 UNION ALL SELECT g.* FROM graph0 g, search_graph sg WHERE g.f = sg.t AND g.f = 1 ) SEARCH DEPTH FIRST BY f, t SET seq SELECT * FROM search_graph ORDER BY seq ) as foo; ERROR: recursive CTEs are not supported in distributed queries -- -- https://github.com/citusdata/citus/issues/5258 -- CREATE TABLE nummultirange_test (nmr NUMMULTIRANGE) USING columnar; INSERT INTO nummultirange_test VALUES('{}'); INSERT INTO nummultirange_test VALUES('{[,)}'); INSERT INTO nummultirange_test VALUES('{[3,]}'); INSERT INTO nummultirange_test VALUES('{[, 5)}'); INSERT INTO nummultirange_test VALUES(nummultirange()); INSERT INTO nummultirange_test VALUES(nummultirange(variadic '{}'::numrange[])); INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.1, 2.2))); INSERT INTO nummultirange_test VALUES('{empty}'); INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.7, 1.9))); INSERT INTO nummultirange_test VALUES(nummultirange(numrange(1.7, 1.7, '[]'), numrange(1.9, 2.1))); create table nummultirange_test2(nmr nummultirange) USING columnar; INSERT INTO nummultirange_test2 VALUES('{[, 5)}'); INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2))); INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2))); INSERT INTO nummultirange_test2 VALUES(nummultirange(numrange(1.1, 2.2,'()'))); INSERT INTO nummultirange_test2 VALUES('{}'); select * from nummultirange_test2 where nmr = '{}'; nmr --------------------------------------------------------------------- {} (1 row) select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.2)); nmr --------------------------------------------------------------------- {[1.1,2.2)} {[1.1,2.2)} (2 rows) select * from nummultirange_test2 where nmr = nummultirange(numrange(1.1, 2.3)); nmr --------------------------------------------------------------------- (0 rows) set enable_nestloop=t; set enable_hashjoin=f; set enable_mergejoin=f; select * from nummultirange_test natural join nummultirange_test2 order by nmr; nmr --------------------------------------------------------------------- {} {} {} {} {(,5)} {[1.1,2.2)} {[1.1,2.2)} (7 rows) -- verify that recreating distributed procedures with OUT param gets propagated to workers CREATE OR REPLACE PROCEDURE proc_with_out_param(IN parm1 date, OUT parm2 int) LANGUAGE SQL AS $$ SELECT 1; $$; -- this should error out SELECT create_distributed_function('proc_with_out_param(date,int)'); ERROR: function "proc_with_out_param(date,int)" does not exist -- this should work SELECT create_distributed_function('proc_with_out_param(date)'); NOTICE: procedure pg14.proc_with_out_param is already distributed DETAIL: Citus distributes procedures with CREATE [PROCEDURE|FUNCTION|AGGREGATE] commands create_distributed_function --------------------------------------------------------------------- (1 row) SET client_min_messages TO ERROR; CREATE ROLE r1; SELECT 1 FROM run_command_on_workers($$CREATE ROLE r1;$$); ?column? --------------------------------------------------------------------- 1 1 (2 rows) GRANT EXECUTE ON PROCEDURE proc_with_out_param TO r1; SELECT 1 FROM run_command_on_workers($$GRANT EXECUTE ON PROCEDURE proc_with_out_param TO r1;$$); ?column? --------------------------------------------------------------------- 1 1 (2 rows) RESET client_min_messages; CREATE OR REPLACE PROCEDURE proc_with_out_param(IN parm1 date, OUT parm2 int) LANGUAGE SQL AS $$ SELECT 2; $$; SELECT count(*) FROM (SELECT result FROM run_command_on_workers($$select row(pg_proc.pronargs, pg_proc.proargtypes, pg_proc.prosrc, pg_proc.proowner) from pg_proc where proname = 'proc_with_out_param';$$) UNION select row(pg_proc.pronargs, pg_proc.proargtypes, pg_proc.prosrc, pg_proc.proowner)::text from pg_proc where proname = 'proc_with_out_param') as test; count --------------------------------------------------------------------- 1 (1 row) set client_min_messages to error; drop schema pg14 cascade; create schema pg14; set search_path to pg14; select 1 from citus_add_node('localhost',:master_port,groupid=>0); ?column? --------------------------------------------------------------------- 1 (1 row) -- test adding foreign table to metadata with the guc -- will test truncating foreign tables later CREATE TABLE foreign_table_test (id integer NOT NULL, data text, a bigserial); INSERT INTO foreign_table_test VALUES (1, 'text_test'); SELECT citus_add_local_table_to_metadata('foreign_table_test'); citus_add_local_table_to_metadata --------------------------------------------------------------------- (1 row) CREATE EXTENSION postgres_fdw; CREATE SERVER foreign_server FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'localhost', port :'master_port', dbname 'regression'); CREATE USER MAPPING FOR CURRENT_USER SERVER foreign_server OPTIONS (user 'postgres'); CREATE FOREIGN TABLE foreign_table ( id integer NOT NULL, data text, a bigserial ) SERVER foreign_server OPTIONS (schema_name 'pg14', table_name 'foreign_table_test'); SELECT citus_add_local_table_to_metadata('foreign_table'); citus_add_local_table_to_metadata --------------------------------------------------------------------- (1 row) SELECT count(*) FROM foreign_table; count --------------------------------------------------------------------- 1 (1 row) TRUNCATE foreign_table; -- test truncating foreign tables in the same statement with -- other distributed tables CREATE TABLE foreign_table_test_2 (id integer NOT NULL, data text, a bigserial); CREATE FOREIGN TABLE foreign_table_2 ( id integer NOT NULL, data text, a bigserial ) SERVER foreign_server OPTIONS (schema_name 'pg14', table_name 'foreign_table_test_2'); SELECT citus_add_local_table_to_metadata('foreign_table_2'); citus_add_local_table_to_metadata --------------------------------------------------------------------- (1 row) CREATE TABLE dist_table_1(a int); CREATE TABLE dist_table_2(a int); CREATE TABLE dist_table_3(a int); SELECT create_distributed_table('dist_table_1', 'a'); create_distributed_table --------------------------------------------------------------------- (1 row) SELECT create_distributed_table('dist_table_2', 'a'); create_distributed_table --------------------------------------------------------------------- (1 row) SELECT create_reference_table('dist_table_3'); create_reference_table --------------------------------------------------------------------- (1 row) TRUNCATE foreign_table, foreign_table_2; TRUNCATE dist_table_1, foreign_table, dist_table_2, foreign_table_2, dist_table_3; TRUNCATE dist_table_1, dist_table_2, foreign_table, dist_table_3; TRUNCATE dist_table_1, foreign_table, foreign_table_2, dist_table_3; TRUNCATE dist_table_1, foreign_table, foreign_table_2, dist_table_3, dist_table_2; \c - - - :worker_1_port set search_path to pg14; -- verify the foreign table is truncated SELECT count(*) FROM pg14.foreign_table; count --------------------------------------------------------------------- 0 (1 row) -- should error out TRUNCATE foreign_table; ERROR: truncating foreign tables that are added to metadata can only be executed on the coordinator \c - - - :master_port SET search_path TO pg14; -- an example with CREATE TABLE LIKE, with statistics with expressions CREATE TABLE ctlt1 (a text CHECK (length(a) > 2) PRIMARY KEY, b text); CREATE STATISTICS ctlt1_expr_stat ON (a || b) FROM ctlt1; CREATE TABLE ctlt_all (LIKE ctlt1 INCLUDING ALL); SELECT create_distributed_table('ctlt1', 'a'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE ctlt_all_2 (LIKE ctlt1 INCLUDING ALL); CREATE TABLE compression_and_defaults ( data text COMPRESSION lz4 DEFAULT '"{}"'::text COLLATE "C" NOT NULL PRIMARY KEY, rev text ) WITH ( autovacuum_vacuum_scale_factor='0.01', fillfactor='75' ); SELECT create_distributed_table('compression_and_defaults', 'data', colocate_with:='none'); create_distributed_table --------------------------------------------------------------------- (1 row) CREATE TABLE compression_and_generated_col ( data text COMPRESSION lz4 GENERATED ALWAYS AS (rev || '{]') STORED COLLATE "C" NOT NULL, rev text ) WITH ( autovacuum_vacuum_scale_factor='0.01', fillfactor='75' ); SELECT create_distributed_table('compression_and_generated_col', 'rev', colocate_with:='none'); create_distributed_table --------------------------------------------------------------------- (1 row) -- See that it's enabling the binary option for logical replication BEGIN; SET LOCAL citus.log_remote_commands TO ON; SET LOCAL citus.grep_remote_commands = '%CREATE SUBSCRIPTION%'; SELECT citus_move_shard_placement(980042, 'localhost', :worker_1_port, 'localhost', :worker_2_port, shard_transfer_mode := 'force_logical'); NOTICE: issuing CREATE SUBSCRIPTION citus_shard_move_subscription_xxxxxxx_xxxxxxx CONNECTION 'host=''localhost'' port=xxxxx user=''postgres'' dbname=''regression'' connect_timeout=20' PUBLICATION citus_shard_move_publication_xxxxxxx_xxxxxxx_xxxxxxx WITH (citus_use_authinfo=true, create_slot=false, copy_data=false, enabled=false, slot_name=citus_shard_move_slot_xxxxxxx_xxxxxxx_xxxxxxx, binary=true) DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx citus_move_shard_placement --------------------------------------------------------------------- (1 row) ROLLBACK; -- See that it doesn't enable the binary option for logical replication if we -- disable binary protocol. BEGIN; SET LOCAL citus.log_remote_commands TO ON; SET LOCAL citus.grep_remote_commands = '%CREATE SUBSCRIPTION%'; SET LOCAL citus.enable_binary_protocol = FALSE; SELECT citus_move_shard_placement(980042, 'localhost', :worker_1_port, 'localhost', :worker_2_port, shard_transfer_mode := 'force_logical'); NOTICE: issuing CREATE SUBSCRIPTION citus_shard_move_subscription_xxxxxxx_xxxxxxx CONNECTION 'host=''localhost'' port=xxxxx user=''postgres'' dbname=''regression'' connect_timeout=20' PUBLICATION citus_shard_move_publication_xxxxxxx_xxxxxxx_xxxxxxx WITH (citus_use_authinfo=true, create_slot=false, copy_data=false, enabled=false, slot_name=citus_shard_move_slot_xxxxxxx_xxxxxxx_xxxxxxx) DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx citus_move_shard_placement --------------------------------------------------------------------- (1 row) ROLLBACK; DROP TABLE compression_and_defaults, compression_and_generated_col; -- cleanup set client_min_messages to error; drop extension postgres_fdw cascade; drop schema pg14 cascade; reset client_min_messages; select 1 from citus_remove_node('localhost',:master_port); ?column? --------------------------------------------------------------------- 1 (1 row)