mirror of https://github.com/citusdata/citus.git
458 lines
17 KiB
Plaintext
458 lines
17 KiB
Plaintext
--
|
|
-- MULTI_ALTER_TABLE_STATEMENTS
|
|
--
|
|
|
|
|
|
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 220000;
|
|
|
|
|
|
-- Check that we can run ALTER TABLE statements on distributed tables.
|
|
-- We set the shardid sequence here so that the shardids in this test
|
|
-- aren't affected by changes to the previous tests.
|
|
CREATE TABLE lineitem_alter (
|
|
l_orderkey bigint not null,
|
|
l_partkey integer not null,
|
|
l_suppkey integer not null,
|
|
l_linenumber integer not null,
|
|
l_quantity decimal(15, 2) not null,
|
|
l_extendedprice decimal(15, 2) not null,
|
|
l_discount decimal(15, 2) not null,
|
|
l_tax decimal(15, 2) not null,
|
|
l_returnflag char(1) not null,
|
|
l_linestatus char(1) not null,
|
|
l_shipdate date not null,
|
|
l_commitdate date not null,
|
|
l_receiptdate date not null,
|
|
l_shipinstruct char(25) not null,
|
|
l_shipmode char(10) not null,
|
|
l_comment varchar(44) not null
|
|
);
|
|
SELECT master_create_distributed_table('lineitem_alter', 'l_orderkey', 'append');
|
|
\copy lineitem_alter FROM '@abs_srcdir@/data/lineitem.1.data' with delimiter '|'
|
|
|
|
-- Verify that we can add columns
|
|
|
|
ALTER TABLE lineitem_alter ADD COLUMN float_column FLOAT;
|
|
ALTER TABLE lineitem_alter ADD COLUMN date_column DATE;
|
|
ALTER TABLE lineitem_alter ADD COLUMN int_column1 INTEGER DEFAULT 1;
|
|
ALTER TABLE lineitem_alter ADD COLUMN int_column2 INTEGER DEFAULT 2;
|
|
ALTER TABLE lineitem_alter ADD COLUMN null_column INTEGER;
|
|
|
|
-- show changed schema on one worker
|
|
\c - - - :worker_1_port
|
|
SELECT attname, atttypid::regtype
|
|
FROM
|
|
(SELECT oid FROM pg_class WHERE relname LIKE 'lineitem_alter_%' ORDER BY relname LIMIT 1) pc
|
|
JOIN pg_attribute ON (pc.oid = pg_attribute.attrelid)
|
|
ORDER BY attnum;
|
|
\c - - - :master_port
|
|
|
|
\d lineitem_alter
|
|
SELECT float_column, count(*) FROM lineitem_alter GROUP BY float_column;
|
|
SELECT int_column1, count(*) FROM lineitem_alter GROUP BY int_column1;
|
|
|
|
-- Verify that SET|DROP DEFAULT works
|
|
|
|
ALTER TABLE lineitem_alter ALTER COLUMN float_column SET DEFAULT 1;
|
|
ALTER TABLE lineitem_alter ALTER COLUMN int_column1 DROP DEFAULT;
|
|
|
|
-- \copy to verify that default values take effect
|
|
\copy lineitem_alter (l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate, l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment) FROM '@abs_srcdir@/data/lineitem.1.data' with delimiter '|'
|
|
|
|
SELECT float_column, count(*) FROM lineitem_alter GROUP BY float_column;
|
|
SELECT int_column1, count(*) FROM lineitem_alter GROUP BY int_column1;
|
|
|
|
-- Verify that SET NOT NULL works
|
|
|
|
ALTER TABLE lineitem_alter ALTER COLUMN int_column2 SET NOT NULL;
|
|
\d lineitem_alter
|
|
|
|
-- Drop default so that NULLs will be inserted for this column
|
|
ALTER TABLE lineitem_alter ALTER COLUMN int_column2 DROP DEFAULT;
|
|
|
|
-- \copy should fail because it will try to insert NULLs for a NOT NULL column
|
|
-- Note, this operation will create a table on the workers but it won't be in the metadata
|
|
\copy lineitem_alter (l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate, l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment) FROM '@abs_srcdir@/data/lineitem.1.data' with delimiter '|'
|
|
|
|
-- Verify that DROP NOT NULL works
|
|
|
|
ALTER TABLE lineitem_alter ALTER COLUMN int_column2 DROP NOT NULL;
|
|
\d lineitem_alter
|
|
|
|
-- \copy should succeed now
|
|
\copy lineitem_alter (l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag, l_linestatus, l_shipdate, l_commitdate, l_receiptdate, l_shipinstruct, l_shipmode, l_comment) FROM '@abs_srcdir@/data/lineitem.1.data' with delimiter '|'
|
|
SELECT count(*) from lineitem_alter;
|
|
|
|
-- Verify that SET DATA TYPE works
|
|
|
|
SELECT int_column2, pg_typeof(int_column2), count(*) from lineitem_alter GROUP BY int_column2;
|
|
|
|
ALTER TABLE lineitem_alter ALTER COLUMN int_column2 SET DATA TYPE FLOAT;
|
|
\d lineitem_alter
|
|
|
|
SELECT int_column2, pg_typeof(int_column2), count(*) from lineitem_alter GROUP BY int_column2;
|
|
|
|
-- Verify that DROP COLUMN works
|
|
|
|
ALTER TABLE lineitem_alter DROP COLUMN int_column1;
|
|
ALTER TABLE lineitem_alter DROP COLUMN float_column;
|
|
ALTER TABLE lineitem_alter DROP COLUMN date_column;
|
|
|
|
-- Verify that RENAME COLUMN works
|
|
ALTER TABLE lineitem_alter RENAME COLUMN l_orderkey TO l_orderkey_renamed;
|
|
SELECT SUM(l_orderkey_renamed) FROM lineitem_alter;
|
|
|
|
-- Verify that IF EXISTS works as expected
|
|
|
|
ALTER TABLE non_existent_table ADD COLUMN new_column INTEGER;
|
|
ALTER TABLE IF EXISTS non_existent_table ADD COLUMN new_column INTEGER;
|
|
ALTER TABLE IF EXISTS lineitem_alter ALTER COLUMN int_column2 SET DATA TYPE INTEGER;
|
|
|
|
ALTER TABLE lineitem_alter DROP COLUMN non_existent_column;
|
|
ALTER TABLE lineitem_alter DROP COLUMN IF EXISTS non_existent_column;
|
|
ALTER TABLE lineitem_alter DROP COLUMN IF EXISTS int_column2;
|
|
|
|
-- Verify with IF EXISTS for extant table
|
|
ALTER TABLE IF EXISTS lineitem_alter RENAME COLUMN l_orderkey_renamed TO l_orderkey;
|
|
SELECT SUM(l_orderkey) FROM lineitem_alter;
|
|
|
|
\d lineitem_alter
|
|
|
|
-- Verify that we can execute commands with multiple subcommands
|
|
|
|
ALTER TABLE lineitem_alter ADD COLUMN int_column1 INTEGER,
|
|
ADD COLUMN int_column2 INTEGER;
|
|
\d lineitem_alter
|
|
|
|
ALTER TABLE lineitem_alter ADD COLUMN int_column3 INTEGER,
|
|
ALTER COLUMN int_column1 SET STATISTICS 10;
|
|
|
|
ALTER TABLE lineitem_alter DROP COLUMN int_column1, DROP COLUMN int_column2;
|
|
\d lineitem_alter
|
|
|
|
-- Verify that we cannot execute alter commands on the distribution column
|
|
|
|
ALTER TABLE lineitem_alter ALTER COLUMN l_orderkey DROP NOT NULL;
|
|
ALTER TABLE lineitem_alter DROP COLUMN l_orderkey;
|
|
|
|
-- Verify that we error out on unsupported statement types
|
|
|
|
ALTER TABLE lineitem_alter ALTER COLUMN l_orderkey SET STATISTICS 100;
|
|
ALTER TABLE lineitem_alter DROP CONSTRAINT IF EXISTS non_existent_contraint;
|
|
ALTER TABLE lineitem_alter SET WITHOUT OIDS;
|
|
|
|
-- Verify that we error out in case of postgres errors on supported statement
|
|
-- types
|
|
|
|
ALTER TABLE lineitem_alter ADD COLUMN new_column non_existent_type;
|
|
ALTER TABLE lineitem_alter ALTER COLUMN null_column SET NOT NULL;
|
|
ALTER TABLE lineitem_alter ALTER COLUMN l_partkey SET DEFAULT 'a';
|
|
|
|
-- Verify that we error out on non-column RENAME statements
|
|
|
|
ALTER TABLE lineitem_alter RENAME TO lineitem_renamed;
|
|
ALTER TABLE lineitem_alter RENAME CONSTRAINT constraint_a TO constraint_b;
|
|
|
|
-- Verify that IF EXISTS works as expected with RENAME statements
|
|
|
|
ALTER TABLE non_existent_table RENAME TO non_existent_table_renamed;
|
|
ALTER TABLE IF EXISTS non_existent_table RENAME TO non_existent_table_renamed;
|
|
ALTER TABLE IF EXISTS non_existent_table RENAME COLUMN column1 TO column2;
|
|
|
|
-- Verify that none of the failed alter table commands took effect on the master
|
|
-- node
|
|
\d lineitem_alter
|
|
|
|
-- verify that non-propagated ddl commands are allowed inside a transaction block
|
|
SET citus.enable_ddl_propagation to false;
|
|
BEGIN;
|
|
CREATE INDEX temp_index_1 ON lineitem_alter(l_linenumber);
|
|
COMMIT;
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
DROP INDEX temp_index_1;
|
|
|
|
-- verify that single distributed ddl commands are allowed inside a transaction block
|
|
SET citus.enable_ddl_propagation to true;
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
COMMIT;
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
DROP INDEX temp_index_2;
|
|
|
|
-- and so are multiple ddl statements
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
ALTER TABLE lineitem_alter ADD COLUMN first integer;
|
|
COMMIT;
|
|
|
|
\d lineitem_alter
|
|
|
|
ALTER TABLE lineitem_alter DROP COLUMN first;
|
|
DROP INDEX temp_index_2;
|
|
|
|
-- ensure that user-specified rollback causes full rollback
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
CREATE INDEX temp_index_3 ON lineitem_alter(l_partkey);
|
|
ROLLBACK;
|
|
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
|
|
-- ensure that errors cause full rollback
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
ROLLBACK;
|
|
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
|
|
-- verify that SAVEPOINT is allowed...
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
SAVEPOINT my_savepoint;
|
|
CREATE INDEX temp_index_3 ON lineitem_alter(l_partkey);
|
|
ROLLBACK;
|
|
|
|
-- but that actually rolling back to it is not
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
SAVEPOINT my_savepoint;
|
|
CREATE INDEX temp_index_3 ON lineitem_alter(l_partkey);
|
|
ROLLBACK TO my_savepoint;
|
|
COMMIT;
|
|
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
|
|
-- Add column on only one worker...
|
|
\c - - - :worker_2_port
|
|
ALTER TABLE lineitem_alter_220000 ADD COLUMN first integer;
|
|
\c - - - :master_port
|
|
|
|
-- and try to add it in a multi-statement block, which fails
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
ALTER TABLE lineitem_alter ADD COLUMN first integer;
|
|
COMMIT;
|
|
|
|
-- Nothing from the block should have committed
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
|
|
-- Create single-shard table (to avoid deadlocks in the upcoming test hackery)
|
|
CREATE TABLE single_shard_items (id integer, name text);
|
|
SELECT master_create_distributed_table('single_shard_items', 'id', 'hash');
|
|
SELECT master_create_worker_shards('single_shard_items', 1, 2);
|
|
|
|
-- Drop the column from the worker...
|
|
\c - - - :worker_2_port
|
|
ALTER TABLE lineitem_alter_220000 DROP COLUMN first;
|
|
|
|
-- Create table to trigger at-xact-end (deferred) failure
|
|
CREATE TABLE ddl_commands (command text UNIQUE DEFERRABLE INITIALLY DEFERRED);
|
|
|
|
-- Use an event trigger to log all DDL event tags in it
|
|
CREATE FUNCTION log_ddl_tag() RETURNS event_trigger AS $ldt$
|
|
BEGIN
|
|
INSERT INTO ddl_commands VALUES (tg_tag);
|
|
END;
|
|
$ldt$ LANGUAGE plpgsql;
|
|
|
|
CREATE EVENT TRIGGER log_ddl_tag ON ddl_command_end EXECUTE PROCEDURE log_ddl_tag();
|
|
|
|
\c - - - :master_port
|
|
-- The above trigger will cause failure at transaction end on one placement.
|
|
-- We'll test 2PC first, as it should handle this "best" (no divergence)
|
|
SET citus.multi_shard_commit_protocol TO '2pc';
|
|
BEGIN;
|
|
CREATE INDEX single_index_2 ON single_shard_items(id);
|
|
CREATE INDEX single_index_3 ON single_shard_items(name);
|
|
COMMIT;
|
|
|
|
-- Nothing from the block should have committed
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'single_shard_items' ORDER BY 1;
|
|
|
|
-- Now try with 2pc off
|
|
RESET citus.multi_shard_commit_protocol;
|
|
BEGIN;
|
|
CREATE INDEX single_index_2 ON single_shard_items(id);
|
|
CREATE INDEX single_index_3 ON single_shard_items(name);
|
|
COMMIT;
|
|
|
|
-- The block should have committed with a warning
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'single_shard_items' ORDER BY 1;
|
|
|
|
\c - - - :worker_2_port
|
|
DROP EVENT TRIGGER log_ddl_tag;
|
|
DROP FUNCTION log_ddl_tag();
|
|
DROP TABLE ddl_commands;
|
|
|
|
\c - - - :master_port
|
|
-- Distributed SELECTs cannot appear after ALTER
|
|
BEGIN;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
SELECT count(*) FROM lineitem_alter;
|
|
COMMIT;
|
|
|
|
-- but are allowed before
|
|
BEGIN;
|
|
SELECT count(*) FROM lineitem_alter;
|
|
CREATE INDEX temp_index_2 ON lineitem_alter(l_orderkey);
|
|
COMMIT;
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
DROP INDEX temp_index_2;
|
|
|
|
--- verify that distributed ddl commands can be used with 2pc
|
|
SET citus.multi_shard_commit_protocol TO '2pc';
|
|
CREATE INDEX temp_index_3 ON lineitem_alter(l_orderkey);
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
DROP INDEX temp_index_3;
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
RESET citus.multi_shard_commit_protocol;
|
|
|
|
-- verify that not any of shard placements are marked as failed when a query failure occurs
|
|
CREATE TABLE test_ab (a int, b int);
|
|
SELECT master_create_distributed_table('test_ab', 'a', 'hash');
|
|
SELECT master_create_worker_shards('test_ab', 8, 2);
|
|
INSERT INTO test_ab VALUES (2, 10);
|
|
INSERT INTO test_ab VALUES (2, 11);
|
|
CREATE UNIQUE INDEX temp_unique_index_1 ON test_ab(a);
|
|
SELECT shardid FROM pg_dist_shard_placement NATURAL JOIN pg_dist_shard
|
|
WHERE logicalrelid='test_ab'::regclass AND shardstate=3;
|
|
|
|
-- Check that the schema on the worker still looks reasonable
|
|
\c - - - :worker_1_port
|
|
SELECT attname, atttypid::regtype
|
|
FROM
|
|
(SELECT oid FROM pg_class WHERE relname LIKE 'lineitem_alter_%' ORDER BY relname LIMIT 1) pc
|
|
JOIN pg_attribute ON (pc.oid = pg_attribute.attrelid)
|
|
ORDER BY attnum;
|
|
\c - - - :master_port
|
|
|
|
-- verify that we don't intercept DDL commands if propagation is turned off
|
|
SET citus.enable_ddl_propagation to false;
|
|
|
|
-- table rename statement can be performed now
|
|
ALTER TABLE lineitem_alter RENAME TO lineitem_renamed;
|
|
-- verify rename is performed
|
|
SELECT relname FROM pg_class WHERE relname = 'lineitem_alter' or relname = 'lineitem_renamed';
|
|
|
|
-- revert it to original name
|
|
ALTER TABLE lineitem_renamed RENAME TO lineitem_alter;
|
|
|
|
-- this column is added to master table and not workers
|
|
ALTER TABLE lineitem_alter ADD COLUMN column_only_added_to_master int;
|
|
|
|
-- verify newly added column is not present in a worker shard
|
|
\c - - - :worker_1_port
|
|
SELECT column_only_added_to_master FROM lineitem_alter_220000 LIMIT 0;
|
|
\c - - - :master_port
|
|
|
|
-- ddl propagation flag is reset to default, disable it again
|
|
SET citus.enable_ddl_propagation to false;
|
|
|
|
-- following query succeeds since it accesses an previously existing column
|
|
SELECT l_orderkey FROM lineitem_alter LIMIT 0;
|
|
|
|
-- make master and workers have the same schema again
|
|
ALTER TABLE lineitem_alter DROP COLUMN column_only_added_to_master;
|
|
-- now this should succeed
|
|
SELECT * FROM lineitem_alter LIMIT 0;
|
|
|
|
-- previously unsupported statements are accepted by postgresql now
|
|
ALTER TABLE lineitem_alter ALTER COLUMN l_orderkey SET STATISTICS 100;
|
|
ALTER TABLE lineitem_alter DROP CONSTRAINT IF EXISTS non_existent_contraint;
|
|
ALTER TABLE lineitem_alter SET WITHOUT OIDS;
|
|
|
|
-- even distribution column can be dropped however postgresql prevents this.
|
|
ALTER TABLE lineitem_alter DROP COLUMN l_orderkey;
|
|
|
|
-- Even unique indexes on l_partkey (non-partition column) are allowed.
|
|
-- Citus would have prevented that.
|
|
CREATE UNIQUE INDEX unique_lineitem_partkey on lineitem_alter(l_partkey);
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter';
|
|
|
|
-- verify index is not created on worker
|
|
\c - - - :worker_1_port
|
|
SELECT indexname, tablename FROM pg_indexes WHERE tablename like 'lineitem_alter_%';
|
|
\c - - - :master_port
|
|
|
|
-- verify alter table and drop sequence in the same transaction does not cause deadlock
|
|
CREATE TABLE sequence_deadlock_test (a serial, b serial);
|
|
SELECT create_distributed_table('sequence_deadlock_test', 'a');
|
|
|
|
BEGIN;
|
|
ALTER TABLE sequence_deadlock_test ADD COLUMN c int;
|
|
DROP SEQUENCE sequence_deadlock_test_b_seq CASCADE;
|
|
END;
|
|
|
|
DROP TABLE sequence_deadlock_test;
|
|
|
|
-- verify enable/disable trigger all works
|
|
|
|
SET citus.shard_replication_factor TO 1;
|
|
SET citus.shard_count TO 1;
|
|
|
|
CREATE TABLE trigger_table (
|
|
id int,
|
|
value text
|
|
);
|
|
|
|
SELECT create_distributed_table('trigger_table', 'id');
|
|
|
|
-- first set a trigger on a shard
|
|
\c - - - :worker_1_port
|
|
|
|
CREATE FUNCTION update_value() RETURNS trigger AS $up$
|
|
BEGIN
|
|
NEW.value := 'trigger enabled';
|
|
RETURN NEW;
|
|
END;
|
|
$up$ LANGUAGE plpgsql;
|
|
|
|
CREATE TRIGGER update_value
|
|
BEFORE INSERT ON trigger_table_220056
|
|
FOR EACH ROW EXECUTE PROCEDURE update_value();
|
|
|
|
\c - - - :master_port
|
|
INSERT INTO trigger_table VALUES (1, 'trigger disabled');
|
|
SELECT value, count(*) FROM trigger_table GROUP BY value ORDER BY value;
|
|
|
|
ALTER TABLE trigger_table DISABLE TRIGGER ALL;
|
|
INSERT INTO trigger_table VALUES (1, 'trigger disabled');
|
|
SELECT value, count(*) FROM trigger_table GROUP BY value ORDER BY value;
|
|
|
|
ALTER TABLE trigger_table ENABLE TRIGGER ALL;
|
|
INSERT INTO trigger_table VALUES (1, 'trigger disabled');
|
|
SELECT value, count(*) FROM trigger_table GROUP BY value ORDER BY value;
|
|
|
|
DROP TABLE trigger_table;
|
|
|
|
-- test ALTER TABLE ALL IN TABLESPACE
|
|
-- we expect that it will warn out
|
|
CREATE TABLESPACE super_fast_ssd LOCATION '@abs_srcdir@/data';
|
|
ALTER TABLE ALL IN TABLESPACE pg_default SET TABLESPACE super_fast_ssd;
|
|
ALTER TABLE ALL IN TABLESPACE super_fast_ssd SET TABLESPACE pg_default;
|
|
DROP TABLESPACE super_fast_ssd;
|
|
|
|
-- Cleanup the table and its shards
|
|
SET citus.enable_ddl_propagation to true;
|
|
SELECT master_apply_delete_command('DELETE FROM lineitem_alter');
|
|
DROP TABLE lineitem_alter;
|
|
-- check that nothing's left over on workers, other than the leftover shard created
|
|
-- during the unsuccessful COPY
|
|
\c - - - :worker_1_port
|
|
SELECT relname FROM pg_class WHERE relname LIKE 'lineitem_alter%';
|
|
\c - - - :master_port
|
|
|
|
-- Test alter table with drop table in the same transaction
|
|
BEGIN;
|
|
CREATE TABLE test_table_1(id int);
|
|
SELECT create_distributed_table('test_table_1','id');
|
|
ALTER TABLE test_table_1 ADD CONSTRAINT u_key UNIQUE(id);
|
|
DROP TABLE test_table_1;
|
|
END;
|
|
|
|
-- There should be no test_table_1 shard on workers
|
|
\c - - - :worker_1_port
|
|
SELECT relname FROM pg_class WHERE relname LIKE 'test_table_1%';
|
|
\c - - - :master_port
|