From 08606526d55da9551f82e70fa9a4c094b45c734d Mon Sep 17 00:00:00 2001 From: Oliver Tan Date: Wed, 13 Jan 2021 18:55:20 +1100 Subject: [PATCH] sql: implement index changes of PARTITION ALL BY on CREATE TABLE Release note (sql change): Implemented PARTITION ALL BY syntax for CREATE TABLE, which automatically partitions the table, and all indexes, with the same partitioning scheme. --- .../testdata/logic_test/partitioning | 5 - .../testdata/logic_test/partitioning_implicit | 107 +++++++++++++++++- pkg/sql/create_table.go | 97 ++++++++++------ 3 files changed, 164 insertions(+), 45 deletions(-) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/partitioning b/pkg/ccl/logictestccl/testdata/logic_test/partitioning index b3795d9d7b6f..83f2e1cb9abb 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/partitioning +++ b/pkg/ccl/logictestccl/testdata/logic_test/partitioning @@ -17,11 +17,6 @@ CREATE TABLE t (a INT, b INT, c INT) PARTITION BY LIST (a) ( PARTITION p1 VALUES IN (0) ) -statement error PARTITION ALL BY not yet implemented -CREATE TABLE t (a INT, b INT) PARTITION ALL BY LIST (b) ( - PARTITION p1 VALUES IN (0) -) - statement error declared partition columns \(a, b, c\) exceed the number of columns in index being partitioned \(a, b\) CREATE TABLE t (a INT, b INT, c INT, PRIMARY KEY (a, b)) PARTITION BY LIST (a, b, c) ( PARTITION p1 VALUES IN (0) diff --git a/pkg/ccl/logictestccl/testdata/logic_test/partitioning_implicit b/pkg/ccl/logictestccl/testdata/logic_test/partitioning_implicit index b6c4fe33d04c..c07310cee9f6 100644 --- a/pkg/ccl/logictestccl/testdata/logic_test/partitioning_implicit +++ b/pkg/ccl/logictestccl/testdata/logic_test/partitioning_implicit @@ -1,5 +1,25 @@ # LogicTest: local +statement error declared partition columns \(partition_by\) do not match first 1 columns in index being partitioned \(a\) +CREATE TABLE t ( + pk INT PRIMARY KEY, + partition_by int, + a INT, + INDEX (a) PARTITION BY LIST (partition_by) ( + PARTITION one VALUES IN (1), + PARTITION two VALUES IN (2) + ) +) + +statement error PARTITION ALL BY LIST/RANGE is currently experimental +CREATE TABLE public.t ( + pk int PRIMARY KEY, + partition_by int +) PARTITION ALL BY LIST (partition_by) ( + PARTITION one VALUES IN (1), + PARTITION two VALUES IN (2) +) + statement ok SET experimental_enable_implicit_column_partitioning = true @@ -113,11 +133,11 @@ WHERE indrelid = (SELECT oid FROM pg_class WHERE relname = 't') ORDER BY 1,2,3 ---- indexrelid indrelid indkey indclass indoption indcollation -450499960 55 3 0 2 0 -450499961 55 4 0 2 0 -450499963 55 1 0 2 0 -450499966 55 2 3 4 0 0 0 2 2 2 0 0 0 -450499967 55 5 0 2 0 +969972496 57 2 3 4 0 0 0 2 2 2 0 0 0 +969972497 57 5 0 2 0 +969972501 57 1 0 2 0 +969972502 57 3 0 2 0 +969972503 57 4 0 2 0 query TTB colnames SELECT index_name, column_name, implicit FROM crdb_internal.index_columns @@ -161,3 +181,80 @@ statement error cannot ALTER TABLE PARTITION BY on table which already has impli ALTER TABLE t PARTITION BY LIST (a) ( PARTITION pk_implicit VALUES IN (1) ) + +statement error PARTITION ALL BY not yet implemented +ALTER TABLE t PARTITION ALL BY LIST (a) ( + PARTITION pk_implicit VALUES IN (1) +) + +statement ok +DROP TABLE t + +statement error cannot define PARTITION BY on an index if the table has a PARTITION ALL BY definition +CREATE TABLE public.t ( + pk int PRIMARY KEY, + partition_by int, + a int, + INDEX(a) PARTITION BY LIST (partition_by) ( + PARTITION one VALUES IN (1) + ) +) PARTITION ALL BY LIST (partition_by) ( + PARTITION one VALUES IN (1), + PARTITION two VALUES IN (2) +) + +statement error cannot define PARTITION BY on an unique constraint if the table has a PARTITION ALL BY definition +CREATE TABLE public.t ( + pk int PRIMARY KEY, + partition_by int, + a int, + UNIQUE(a) PARTITION BY LIST (partition_by) ( + PARTITION one VALUES IN (1) + ) +) PARTITION ALL BY LIST (partition_by) ( + PARTITION one VALUES IN (1), + PARTITION two VALUES IN (2) +) + +statement ok +CREATE TABLE public.t ( + pk int PRIMARY KEY, + partition_by int, + a int, + b int, + c int, + d int, + INDEX (a), + UNIQUE (b), + FAMILY (pk, partition_by, a, b, c, d) +) PARTITION ALL BY LIST (partition_by) ( + PARTITION one VALUES IN (1), + PARTITION two VALUES IN (2) +) + +# TODO(#58878): PARTITION BY should be hidden for index definitions. +query T +SELECT create_statement FROM [SHOW CREATE TABLE t] +---- +CREATE TABLE public.t ( + pk INT8 NOT NULL, + partition_by INT8 NULL, + a INT8 NULL, + b INT8 NULL, + c INT8 NULL, + d INT8 NULL, + CONSTRAINT "primary" PRIMARY KEY (pk ASC), + INDEX t_a_idx (a ASC) PARTITION BY LIST (partition_by) ( + PARTITION one VALUES IN ((1)), + PARTITION two VALUES IN ((2)) + ), + UNIQUE INDEX t_b_key (b ASC) PARTITION BY LIST (partition_by) ( + PARTITION one VALUES IN ((1)), + PARTITION two VALUES IN ((2)) + ), + FAMILY fam_0_pk_partition_by_a_b_c_d (pk, partition_by, a, b, c, d) +) PARTITION BY LIST (partition_by) ( + PARTITION one VALUES IN ((1)), + PARTITION two VALUES IN ((2)) +) +-- Warning: Partitioned table with no zone configurations. diff --git a/pkg/sql/create_table.go b/pkg/sql/create_table.go index 6f5c1b6a3c44..50948fa9a2dc 100644 --- a/pkg/sql/create_table.go +++ b/pkg/sql/create_table.go @@ -1511,6 +1511,21 @@ func NewTableDesc( } return nil } + + var partitionByAll *tree.PartitionBy + if n.PartitionByTable != nil && n.PartitionByTable.All { + if !evalCtx.SessionData.ImplicitColumnPartitioningEnabled { + return nil, errors.WithHint( + pgerror.New( + pgcode.FeatureNotSupported, + "PARTITION ALL BY LIST/RANGE is currently experimental", + ), + "to enable, use SET experimental_enable_implicit_column_partitioning = true", + ) + } + partitionByAll = n.PartitionByTable.PartitionBy + } + idxValidator := schemaexpr.MakeIndexPredicateValidator(ctx, n.Table, &desc, semaCtx) for _, def := range n.Defs { switch d := def.(type) { @@ -1561,14 +1576,23 @@ func NewTableDesc( idx.GeoConfig = *geoindex.DefaultGeographyIndexConfig() } } - if d.PartitionByIndex.ContainsPartitions() { + if d.PartitionByIndex.ContainsPartitions() || partitionByAll != nil { + partitionBy := partitionByAll + if partitionByAll == nil { + partitionBy = d.PartitionByIndex.PartitionBy + } else if d.PartitionByIndex.ContainsPartitions() { + return nil, pgerror.New( + pgcode.FeatureNotSupported, + "cannot define PARTITION BY on an index if the table has a PARTITION ALL BY definition", + ) + } var numImplicitColumns int var err error idx, numImplicitColumns, err = detectImplicitPartitionColumns( evalCtx, &desc, idx, - d.PartitionByIndex.PartitionBy, + partitionBy, ) if err != nil { return nil, err @@ -1580,7 +1604,7 @@ func NewTableDesc( &desc, &idx, numImplicitColumns, - d.PartitionByIndex.PartitionBy, + partitionBy, ) if err != nil { return nil, err @@ -1633,14 +1657,24 @@ func NewTableDesc( if err := idx.FillColumns(d.Columns); err != nil { return nil, err } - if d.PartitionByIndex.ContainsPartitions() { + if d.PartitionByIndex.ContainsPartitions() || partitionByAll != nil { + partitionBy := partitionByAll + if partitionByAll == nil { + partitionBy = d.PartitionByIndex.PartitionBy + } else if d.PartitionByIndex.ContainsPartitions() { + return nil, pgerror.New( + pgcode.FeatureNotSupported, + "cannot define PARTITION BY on an unique constraint if the table has a PARTITION ALL BY definition", + ) + } + var numImplicitColumns int var err error idx, numImplicitColumns, err = detectImplicitPartitionColumns( evalCtx, &desc, idx, - d.PartitionByIndex.PartitionBy, + partitionBy, ) if err != nil { return nil, err @@ -1652,7 +1686,7 @@ func NewTableDesc( &desc, &idx, numImplicitColumns, - d.PartitionByIndex.PartitionBy, + partitionBy, ) if err != nil { return nil, err @@ -1759,37 +1793,30 @@ func NewTableDesc( } } - // Do not use ContainsPartitions() for this check, as we may have to do something special for - // PARTITION BY NOTHING. - if n.PartitionByTable != nil { - if n.PartitionByTable.All { - return nil, unimplemented.New("CREATE TABLE PARTITION ALL BY", "PARTITION ALL BY not yet implemented") + if n.PartitionByTable.ContainsPartitions() { + newPrimaryIndex, numImplicitColumns, err := detectImplicitPartitionColumns( + evalCtx, + &desc, + *desc.GetPrimaryIndex().IndexDesc(), + n.PartitionByTable.PartitionBy, + ) + if err != nil { + return nil, err } - if n.PartitionByTable.PartitionBy != nil { - newPrimaryIndex, numImplicitColumns, err := detectImplicitPartitionColumns( - evalCtx, - &desc, - *desc.GetPrimaryIndex().IndexDesc(), - n.PartitionByTable.PartitionBy, - ) - if err != nil { - return nil, err - } - partitioning, err := CreatePartitioning( - ctx, - st, - evalCtx, - &desc, - &newPrimaryIndex, - numImplicitColumns, - n.PartitionByTable.PartitionBy, - ) - if err != nil { - return nil, err - } - newPrimaryIndex.Partitioning = partitioning - desc.SetPrimaryIndex(newPrimaryIndex) + partitioning, err := CreatePartitioning( + ctx, + st, + evalCtx, + &desc, + &newPrimaryIndex, + numImplicitColumns, + n.PartitionByTable.PartitionBy, + ) + if err != nil { + return nil, err } + newPrimaryIndex.Partitioning = partitioning + desc.SetPrimaryIndex(newPrimaryIndex) } // Once all the IDs have been allocated, we can add the Sequence dependencies