From ef927688fa233b591308e587f36c5b2cb0c36565 Mon Sep 17 00:00:00 2001 From: Hadi Moshayedi Date: Fri, 29 Jan 2021 10:07:16 -0800 Subject: [PATCH] Columnar: Fix ALTER TABLE ... ADD COLUMN. --- src/backend/columnar/cstore_tableam.c | 7 ++- src/test/regress/expected/am_alter.out | 73 +++++++++++++++++++++++++- src/test/regress/sql/am_alter.sql | 44 +++++++++++++++- 3 files changed, 118 insertions(+), 6 deletions(-) diff --git a/src/backend/columnar/cstore_tableam.c b/src/backend/columnar/cstore_tableam.c index 43ce631ba..4a5b3026f 100644 --- a/src/backend/columnar/cstore_tableam.c +++ b/src/backend/columnar/cstore_tableam.c @@ -112,10 +112,9 @@ static Datum * detoast_values(TupleDesc tupleDesc, Datum *orig_values, bool *isn static TupleTableSlotOps TTSOpsColumnar; static List * -RelationColumnList(Relation rel) +RelationColumnList(TupleDesc tupdesc) { List *columnList = NIL; - TupleDesc tupdesc = RelationGetDescr(rel); for (int i = 0; i < tupdesc->natts; i++) { @@ -234,7 +233,7 @@ static TableReadState * init_columnar_read_state(Relation relation, TupleDesc tupdesc, Bitmapset *attr_needed, List *scanQual) { - List *columnList = RelationColumnList(relation); + List *columnList = RelationColumnList(tupdesc); ListCell *columnCell = NULL; List *neededColumnList = NIL; @@ -641,7 +640,7 @@ columnar_relation_copy_for_cluster(Relation OldHeap, Relation NewHeap, targetDesc); TableReadState *readState = ColumnarBeginRead(OldHeap, sourceDesc, - RelationColumnList(OldHeap), NULL); + RelationColumnList(sourceDesc), NULL); Datum *values = palloc0(sourceDesc->natts * sizeof(Datum)); bool *nulls = palloc0(sourceDesc->natts * sizeof(bool)); diff --git a/src/test/regress/expected/am_alter.out b/src/test/regress/expected/am_alter.out index 15542d932..a5e82ad3e 100644 --- a/src/test/regress/expected/am_alter.out +++ b/src/test/regress/expected/am_alter.out @@ -1,6 +1,8 @@ -- --- Testing ALTER TABLE on cstore_fdw tables. +-- Testing ALTER TABLE on columnar tables. -- +CREATE SCHEMA columnar_alter; +SET search_path tO columnar_alter, public; CREATE TABLE test_alter_table (a int, b int, c int) USING columnar; WITH sample_data AS (VALUES (1, 2, 3), @@ -171,3 +173,72 @@ ALTER TABLE test_alter_table ALTER COLUMN j TYPE int; ALTER TABLE test_alter_table ALTER COLUMN k TYPE varchar(20); ALTER TABLE test_alter_table ALTER COLUMN k TYPE text; DROP TABLE test_alter_table; +-- https://github.com/citusdata/citus/issues/4602 +create domain str_domain as text not null; +create table domain_test (a int, b int) using columnar; +insert into domain_test values (1, 2); +insert into domain_test values (1, 2); +-- the following should error out since the domain is not nullable +alter table domain_test add column c str_domain; +ERROR: domain str_domain does not allow null values +-- but this should succeed +alter table domain_test add column c str_domain DEFAULT 'x'; +SELECT * FROM domain_test; + a | b | c +--------------------------------------------------------------------- + 1 | 2 | x + 1 | 2 | x +(2 rows) + +set default_table_access_method TO 'columnar'; +CREATE TABLE has_volatile AS +SELECT * FROM generate_series(1,10) id; +ALTER TABLE has_volatile ADD col4 int DEFAULT (random() * 10000)::int; +SELECT id, col4 < 10000 FROM has_volatile ORDER BY id; + id | ?column? +--------------------------------------------------------------------- + 1 | t + 2 | t + 3 | t + 4 | t + 5 | t + 6 | t + 7 | t + 8 | t + 9 | t + 10 | t +(10 rows) + +-- https://github.com/citusdata/citus/issues/4601 +CREATE TABLE itest13 (a int) using columnar; +INSERT INTO itest13 VALUES (1), (2), (3); +ALTER TABLE itest13 ADD COLUMN c int GENERATED BY DEFAULT AS IDENTITY; +SELECT * FROM itest13 ORDER BY a; + a | c +--------------------------------------------------------------------- + 1 | 1 + 2 | 2 + 3 | 3 +(3 rows) + +create table atacc1 (a int) using columnar; +insert into atacc1 values(1); +-- should error out. It previously crashed. +alter table atacc1 + add column b float8 not null default random(), + add primary key(a); +ERROR: indexes not supported for columnar tables +-- Add a generate column with an expression value +create table test_gen_ex (x int) using columnar; +INSERT INTO test_gen_ex VALUES (1), (2), (3); +ALTER TABLE test_gen_ex ADD COLUMN y int generated always as (x+1) stored; +SELECT * FROM test_gen_ex; + x | y +--------------------------------------------------------------------- + 1 | 2 + 2 | 3 + 3 | 4 +(3 rows) + +SET client_min_messages TO WARNING; +DROP SCHEMA columnar_alter CASCADE; diff --git a/src/test/regress/sql/am_alter.sql b/src/test/regress/sql/am_alter.sql index 13f17fef2..c3efad28a 100644 --- a/src/test/regress/sql/am_alter.sql +++ b/src/test/regress/sql/am_alter.sql @@ -1,7 +1,10 @@ -- --- Testing ALTER TABLE on cstore_fdw tables. +-- Testing ALTER TABLE on columnar tables. -- +CREATE SCHEMA columnar_alter; +SET search_path tO columnar_alter, public; + CREATE TABLE test_alter_table (a int, b int, c int) USING columnar; WITH sample_data AS (VALUES @@ -83,3 +86,42 @@ ALTER TABLE test_alter_table ALTER COLUMN k TYPE varchar(20); ALTER TABLE test_alter_table ALTER COLUMN k TYPE text; DROP TABLE test_alter_table; + +-- https://github.com/citusdata/citus/issues/4602 +create domain str_domain as text not null; +create table domain_test (a int, b int) using columnar; +insert into domain_test values (1, 2); +insert into domain_test values (1, 2); +-- the following should error out since the domain is not nullable +alter table domain_test add column c str_domain; +-- but this should succeed +alter table domain_test add column c str_domain DEFAULT 'x'; +SELECT * FROM domain_test; + +set default_table_access_method TO 'columnar'; +CREATE TABLE has_volatile AS +SELECT * FROM generate_series(1,10) id; +ALTER TABLE has_volatile ADD col4 int DEFAULT (random() * 10000)::int; +SELECT id, col4 < 10000 FROM has_volatile ORDER BY id; + +-- https://github.com/citusdata/citus/issues/4601 +CREATE TABLE itest13 (a int) using columnar; +INSERT INTO itest13 VALUES (1), (2), (3); +ALTER TABLE itest13 ADD COLUMN c int GENERATED BY DEFAULT AS IDENTITY; +SELECT * FROM itest13 ORDER BY a; + +create table atacc1 (a int) using columnar; +insert into atacc1 values(1); +-- should error out. It previously crashed. +alter table atacc1 + add column b float8 not null default random(), + add primary key(a); + +-- Add a generate column with an expression value +create table test_gen_ex (x int) using columnar; +INSERT INTO test_gen_ex VALUES (1), (2), (3); +ALTER TABLE test_gen_ex ADD COLUMN y int generated always as (x+1) stored; +SELECT * FROM test_gen_ex; + +SET client_min_messages TO WARNING; +DROP SCHEMA columnar_alter CASCADE;