From 7ceb49068e1395ed0ac3a5fc47517f10b094239f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Villemain?= Date: Wed, 26 Feb 2025 16:04:45 +0100 Subject: [PATCH] WIP new test Add more testing for UPDATE with indirection It'll probably be interesting to add more test related to indirection here. --- src/test/regress/expected/indirections.out | 358 +++++++++++++++++++++ src/test/regress/sql/indirections.sql | 206 ++++++++++++ 2 files changed, 564 insertions(+) create mode 100644 src/test/regress/expected/indirections.out create mode 100644 src/test/regress/sql/indirections.sql diff --git a/src/test/regress/expected/indirections.out b/src/test/regress/expected/indirections.out new file mode 100644 index 000000000..a9ef5078a --- /dev/null +++ b/src/test/regress/expected/indirections.out @@ -0,0 +1,358 @@ +SET citus.shard_count TO 2; +SET citus.next_shard_id TO 750000; +SET citus.next_placement_id TO 750000; +CREATE SCHEMA indirections; +SET search_path TO indirections; +-- specific tests related to get_update_query_targetlist_def +-- we test only queries with sublinks, like: +-- ( ... SET (...) = (SELECT ...)) +-- Reference tables +CREATE TABLE test_ref_indirection ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_reference_table('indirections.test_ref_indirection'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE test_ref_indirection_new ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_reference_table('indirections.test_ref_indirection_new'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +-- Distributed tables +CREATE TABLE test_dist_indirection ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_distributed_table('indirections.test_dist_indirection', 'id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE test_dist_indirection_new ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_distributed_table('indirections.test_dist_indirection_new', 'id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- Local tables required ? +-- those should work: +INSERT INTO test_ref_indirection (id, col_bool, col_date, col_int, col_text) + SELECT 1, true, '1970-01-01'::date, 1, 'one'; +INSERT INTO test_dist_indirection (id, col_bool, col_date, col_int, col_text) + SELECT 1, true, '1970-01-01'::date, 1, 'one'; +INSERT INTO test_ref_indirection (id, col_text, col_bool, col_date, col_int) + SELECT 2, 'two', false, '1970-01-01'::date, 2; +INSERT INTO test_dist_indirection (id, col_text, col_bool, col_date, col_int) + SELECT 2, 'two', false, '1970-01-01'::date, 2; +INSERT INTO test_ref_indirection SELECT 3, false, '1970-01-01'::date, 0, 'empty'; +INSERT INTO test_dist_indirection SELECT 3, false, '1970-01-01'::date, 0, 'empty'; +INSERT INTO test_ref_indirection SELECT 4, false, '1970-01-01'::date, 0, 'empty'; +INSERT INTO test_dist_indirection SELECT 4, false, '1970-01-01'::date, 0, 'empty'; +INSERT INTO test_ref_indirection_new SELECT * FROM test_ref_indirection; +INSERT INTO test_dist_indirection_new SELECT * FROM test_dist_indirection; +SELECT * FROM test_ref_indirection ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 01-01-1970 | 1 | one + 2 | f | 01-01-1970 | 2 | two + 3 | f | 01-01-1970 | 0 | empty + 4 | f | 01-01-1970 | 0 | empty +(4 rows) + +SELECT * FROM test_dist_indirection ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 01-01-1970 | 1 | one + 2 | f | 01-01-1970 | 2 | two + 3 | f | 01-01-1970 | 0 | empty + 4 | f | 01-01-1970 | 0 | empty +(4 rows) + +SELECT * FROM test_ref_indirection_new ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 01-01-1970 | 1 | one + 2 | f | 01-01-1970 | 2 | two + 3 | f | 01-01-1970 | 0 | empty + 4 | f | 01-01-1970 | 0 | empty +(4 rows) + +SELECT * FROM test_dist_indirection_new ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 01-01-1970 | 1 | one + 2 | f | 01-01-1970 | 2 | two + 3 | f | 01-01-1970 | 0 | empty + 4 | f | 01-01-1970 | 0 | empty +(4 rows) + +-- now UPDATEs +UPDATE test_ref_indirection + SET (col_bool, col_date, col_int, col_text) + = (SELECT true, '1970-12-31'::date, 1, 'ok') +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 12-31-1970 | 1 | ok + 2 | t | 12-31-1970 | 1 | ok + 3 | t | 12-31-1970 | 1 | ok + 4 | t | 12-31-1970 | 1 | ok +(4 rows) + +UPDATE test_dist_indirection + SET (col_bool, col_date, col_int, col_text) + = (SELECT true, '1970-12-31'::date, 1, 'ok') +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 12-31-1970 | 1 | ok + 2 | t | 12-31-1970 | 1 | ok + 3 | t | 12-31-1970 | 1 | ok + 4 | t | 12-31-1970 | 1 | ok +(4 rows) + +UPDATE test_ref_indirection + SET (col_bool, col_date) = (select true, '1970-06-06'::date) + , (col_int, col_text) = (select 1, 'still ok') +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | still ok + 2 | t | 06-06-1970 | 1 | still ok + 3 | t | 06-06-1970 | 1 | still ok + 4 | t | 06-06-1970 | 1 | still ok +(4 rows) + +UPDATE test_dist_indirection + SET (col_bool, col_date) = (select true, '1970-06-06'::date) + , (col_int, col_text) = (select 1, 'still ok') +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | still ok + 2 | t | 06-06-1970 | 1 | still ok + 3 | t | 06-06-1970 | 1 | still ok + 4 | t | 06-06-1970 | 1 | still ok +(4 rows) + +SELECT * FROM test_ref_indirection ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | still ok + 2 | t | 06-06-1970 | 1 | still ok + 3 | t | 06-06-1970 | 1 | still ok + 4 | t | 06-06-1970 | 1 | still ok +(4 rows) + +SELECT * FROM test_dist_indirection ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | still ok + 2 | t | 06-06-1970 | 1 | still ok + 3 | t | 06-06-1970 | 1 | still ok + 4 | t | 06-06-1970 | 1 | still ok +(4 rows) + +-- but those should not: +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_date, col_text, col_int, col_bool) + = (SELECT '1970-12-31'::date, 'not ok', 2, false) +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type date +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_date, col_text, col_int, col_bool) + = (SELECT '1970-12-31'::date, 'not ok', 2, false) +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type date +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_int, col_date) = (select 2, '1970-06-06'::date) + , (col_text, col_bool) = (select 'not ok', false) +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type integer +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_int, col_date) = (select 2, '1970-06-06'::date) + , (col_text, col_bool) = (select 'not ok', false) +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type integer +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- +-- more restrictive ones, just in case we miss a wrong value +-- +-- those should work +UPDATE test_ref_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | ok + 2 | t | 06-06-1970 | 1 | ok + 3 | t | 06-06-1970 | 1 | ok + 4 | t | 06-06-1970 | 1 | ok +(4 rows) + +UPDATE test_dist_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | ok + 2 | t | 06-06-1970 | 1 | ok + 3 | t | 06-06-1970 | 1 | ok + 4 | t | 06-06-1970 | 1 | ok +(4 rows) + +UPDATE test_ref_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +WHERE id = 1 +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | ok +(1 row) + +UPDATE test_dist_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +WHERE id = 1 +RETURNING *; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | ok +(1 row) + +SELECT * FROM test_ref_indirection ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | ok + 2 | t | 06-06-1970 | 1 | ok + 3 | t | 06-06-1970 | 1 | ok + 4 | t | 06-06-1970 | 1 | ok +(4 rows) + +SELECT * FROM test_dist_indirection ORDER BY id; + id | col_bool | col_date | col_int | col_text +--------------------------------------------------------------------- + 1 | t | 06-06-1970 | 1 | ok + 2 | t | 06-06-1970 | 1 | ok + 3 | t | 06-06-1970 | 1 | ok + 4 | t | 06-06-1970 | 1 | ok +(4 rows) + +-- those should not +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type text +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type text +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +WHERE id = 2 +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type text +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +WHERE id = 2 +RETURNING *; +ERROR: column "col_bool" is of type boolean but expression is of type text +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- several updates in CTE shoult not work +-- TODO wrong ERROR +with qq3 as ( + update test_ref_indirection + SET (col_text, col_bool) + = (SELECT 'full', true) + where id = 3 + returning * +), +qq4 as ( + update test_ref_indirection + SET (col_text, col_bool) + = (SELECT 'fully', true) + where id = 4 + returning * +) +select * from qq3 union all select * from qq4; +ERROR: column "col_bool" is of type boolean but expression is of type text +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +-- TODO wrong ERROR +with qq3 as ( + update test_dist_indirection + SET (col_text, col_bool) + = (SELECT 'full', true) + where id = 3 + returning * +), +qq4 as ( + update test_dist_indirection + SET (col_text, col_bool) + = (SELECT 'fully', true) + where id = 4 + returning * +) +select * from qq3 union all select * from qq4; +ERROR: column "col_bool" is of type boolean but expression is of type text +HINT: You will need to rewrite or cast the expression. +CONTEXT: while executing command on localhost:xxxxx +DROP TABLE test_dist_indirection; +DROP TABLE test_dist_indirection_new; +DROP TABLE test_ref_indirection; +DROP TABLE test_ref_indirection_new; +-- https://github.com/citusdata/citus/issues/4092 +CREATE TABLE update_test ( + a INT DEFAULT 10, + b INT, + c TEXT +); +SELECT create_reference_table('indirections.update_test'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +UPDATE update_test +SET (b,a) = (select a,b from update_test where b = 41 and c = 'car') +WHERE a = 100 AND b = 20; +-- https://github.com/citusdata/citus/pull/5692 +DROP SCHEMA indirections CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table update_test +drop cascades to table update_test_750006 diff --git a/src/test/regress/sql/indirections.sql b/src/test/regress/sql/indirections.sql new file mode 100644 index 000000000..fd8119ff5 --- /dev/null +++ b/src/test/regress/sql/indirections.sql @@ -0,0 +1,206 @@ +SET citus.shard_count TO 2; +SET citus.next_shard_id TO 750000; +SET citus.next_placement_id TO 750000; + +CREATE SCHEMA indirections; +SET search_path TO indirections; + +-- specific tests related to get_update_query_targetlist_def +-- we test only queries with sublinks, like: +-- ( ... SET (...) = (SELECT ...)) + +-- Reference tables +CREATE TABLE test_ref_indirection ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_reference_table('indirections.test_ref_indirection'); + +CREATE TABLE test_ref_indirection_new ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_reference_table('indirections.test_ref_indirection_new'); + +-- Distributed tables +CREATE TABLE test_dist_indirection ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_distributed_table('indirections.test_dist_indirection', 'id'); + +CREATE TABLE test_dist_indirection_new ( + id bigint primary key + , col_bool bool , col_date date , col_int integer , col_text text + ); +SELECT create_distributed_table('indirections.test_dist_indirection_new', 'id'); + +-- Local tables required ? + +-- those should work: +INSERT INTO test_ref_indirection (id, col_bool, col_date, col_int, col_text) + SELECT 1, true, '1970-01-01'::date, 1, 'one'; +INSERT INTO test_dist_indirection (id, col_bool, col_date, col_int, col_text) + SELECT 1, true, '1970-01-01'::date, 1, 'one'; + +INSERT INTO test_ref_indirection (id, col_text, col_bool, col_date, col_int) + SELECT 2, 'two', false, '1970-01-01'::date, 2; +INSERT INTO test_dist_indirection (id, col_text, col_bool, col_date, col_int) + SELECT 2, 'two', false, '1970-01-01'::date, 2; + +INSERT INTO test_ref_indirection SELECT 3, false, '1970-01-01'::date, 0, 'empty'; +INSERT INTO test_dist_indirection SELECT 3, false, '1970-01-01'::date, 0, 'empty'; +INSERT INTO test_ref_indirection SELECT 4, false, '1970-01-01'::date, 0, 'empty'; +INSERT INTO test_dist_indirection SELECT 4, false, '1970-01-01'::date, 0, 'empty'; + +INSERT INTO test_ref_indirection_new SELECT * FROM test_ref_indirection; +INSERT INTO test_dist_indirection_new SELECT * FROM test_dist_indirection; + +SELECT * FROM test_ref_indirection ORDER BY id; +SELECT * FROM test_dist_indirection ORDER BY id; + +SELECT * FROM test_ref_indirection_new ORDER BY id; +SELECT * FROM test_dist_indirection_new ORDER BY id; + +-- now UPDATEs +UPDATE test_ref_indirection + SET (col_bool, col_date, col_int, col_text) + = (SELECT true, '1970-12-31'::date, 1, 'ok') +RETURNING *; +UPDATE test_dist_indirection + SET (col_bool, col_date, col_int, col_text) + = (SELECT true, '1970-12-31'::date, 1, 'ok') +RETURNING *; + +UPDATE test_ref_indirection + SET (col_bool, col_date) = (select true, '1970-06-06'::date) + , (col_int, col_text) = (select 1, 'still ok') +RETURNING *; +UPDATE test_dist_indirection + SET (col_bool, col_date) = (select true, '1970-06-06'::date) + , (col_int, col_text) = (select 1, 'still ok') +RETURNING *; + +SELECT * FROM test_ref_indirection ORDER BY id; +SELECT * FROM test_dist_indirection ORDER BY id; + +-- but those should not: +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_date, col_text, col_int, col_bool) + = (SELECT '1970-12-31'::date, 'not ok', 2, false) +RETURNING *; +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_date, col_text, col_int, col_bool) + = (SELECT '1970-12-31'::date, 'not ok', 2, false) +RETURNING *; + +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_int, col_date) = (select 2, '1970-06-06'::date) + , (col_text, col_bool) = (select 'not ok', false) +RETURNING *; +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_int, col_date) = (select 2, '1970-06-06'::date) + , (col_text, col_bool) = (select 'not ok', false) +RETURNING *; + +-- +-- more restrictive ones, just in case we miss a wrong value +-- +-- those should work +UPDATE test_ref_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +RETURNING *; +UPDATE test_dist_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +RETURNING *; + +UPDATE test_ref_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +WHERE id = 1 +RETURNING *; +UPDATE test_dist_indirection + SET (col_bool, col_text) = (SELECT true, 'ok') +WHERE id = 1 +RETURNING *; + +SELECT * FROM test_ref_indirection ORDER BY id; +SELECT * FROM test_dist_indirection ORDER BY id; + +-- those should not +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +RETURNING *; +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +RETURNING *; + +-- TODO wrong ERROR +UPDATE test_ref_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +WHERE id = 2 +RETURNING *; +-- TODO wrong ERROR +UPDATE test_dist_indirection + SET (col_text, col_bool) = (SELECT 'not ok', false) +WHERE id = 2 +RETURNING *; + +-- several updates in CTE shoult not work +-- TODO wrong ERROR +with qq3 as ( + update test_ref_indirection + SET (col_text, col_bool) + = (SELECT 'full', true) + where id = 3 + returning * +), +qq4 as ( + update test_ref_indirection + SET (col_text, col_bool) + = (SELECT 'fully', true) + where id = 4 + returning * +) +select * from qq3 union all select * from qq4; +-- TODO wrong ERROR +with qq3 as ( + update test_dist_indirection + SET (col_text, col_bool) + = (SELECT 'full', true) + where id = 3 + returning * +), +qq4 as ( + update test_dist_indirection + SET (col_text, col_bool) + = (SELECT 'fully', true) + where id = 4 + returning * +) +select * from qq3 union all select * from qq4; + +DROP TABLE test_dist_indirection; +DROP TABLE test_dist_indirection_new; +DROP TABLE test_ref_indirection; +DROP TABLE test_ref_indirection_new; + +-- https://github.com/citusdata/citus/issues/4092 +CREATE TABLE update_test ( + a INT DEFAULT 10, + b INT, + c TEXT +); +SELECT create_reference_table('indirections.update_test'); +UPDATE update_test +SET (b,a) = (select a,b from update_test where b = 41 and c = 'car') +WHERE a = 100 AND b = 20; + +-- https://github.com/citusdata/citus/pull/5692 + +DROP SCHEMA indirections CASCADE;