From a9de7d968bc8a22b6e0899b66b8a3694ce508e15 Mon Sep 17 00:00:00 2001 From: Monica Xu Date: Tue, 1 Dec 2020 18:33:39 -0500 Subject: [PATCH] sql: Added CREATE SEQ AS postgres compatibility Previously, unimplementedWithIssueDetail error was thrown when an AS in CREATE SEQ AS was encountered. Now we support the AS option for creating sequences. Valid option values are bigint/int8, int/integer/int4, and smallint/int2. The typename value determines the min and max values a sequence can take. Release note (sql change): Enabled CREATE SEQ AS functionality. --- .../sql/bnf/alter_sequence_options_stmt.bnf | 4 +- .../sql/bnf/create_sequence_stmt.bnf | 4 +- docs/generated/sql/bnf/stmt_block.bnf | 3 +- pkg/ccl/importccl/import_stmt_test.go | 41 +++++++++++++++++++ pkg/sql/parser/sql.y | 3 +- pkg/sql/sem/tree/create.go | 7 ++++ pkg/sql/sequence.go | 18 ++++++++ 7 files changed, 74 insertions(+), 6 deletions(-) diff --git a/docs/generated/sql/bnf/alter_sequence_options_stmt.bnf b/docs/generated/sql/bnf/alter_sequence_options_stmt.bnf index b396c7e22f8d..6df294f9f398 100644 --- a/docs/generated/sql/bnf/alter_sequence_options_stmt.bnf +++ b/docs/generated/sql/bnf/alter_sequence_options_stmt.bnf @@ -1,3 +1,3 @@ alter_sequence_options_stmt ::= - 'ALTER' 'SEQUENCE' sequence_name ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) - | 'ALTER' 'SEQUENCE' 'IF' 'EXISTS' sequence_name ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) + 'ALTER' 'SEQUENCE' sequence_name ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) + | 'ALTER' 'SEQUENCE' 'IF' 'EXISTS' sequence_name ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) diff --git a/docs/generated/sql/bnf/create_sequence_stmt.bnf b/docs/generated/sql/bnf/create_sequence_stmt.bnf index 9d2b1cfcd281..82fc4b8bd6c5 100644 --- a/docs/generated/sql/bnf/create_sequence_stmt.bnf +++ b/docs/generated/sql/bnf/create_sequence_stmt.bnf @@ -1,3 +1,3 @@ create_sequence_stmt ::= - 'CREATE' opt_temp 'SEQUENCE' sequence_name ( ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) | ) - | 'CREATE' opt_temp 'SEQUENCE' 'IF' 'NOT' 'EXISTS' sequence_name ( ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) | ) + 'CREATE' opt_temp 'SEQUENCE' sequence_name ( ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) | ) + | 'CREATE' opt_temp 'SEQUENCE' 'IF' 'NOT' 'EXISTS' sequence_name ( ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'AS' typename | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_name | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) | ) diff --git a/docs/generated/sql/bnf/stmt_block.bnf b/docs/generated/sql/bnf/stmt_block.bnf index e0991b6d0875..064f9763f7a8 100644 --- a/docs/generated/sql/bnf/stmt_block.bnf +++ b/docs/generated/sql/bnf/stmt_block.bnf @@ -2482,7 +2482,8 @@ alter_index_cmd ::= partition_by sequence_option_elem ::= - 'NO' 'CYCLE' + 'AS' typename + | 'NO' 'CYCLE' | 'OWNED' 'BY' 'NONE' | 'OWNED' 'BY' column_path | 'INCREMENT' signed_iconst64 diff --git a/pkg/ccl/importccl/import_stmt_test.go b/pkg/ccl/importccl/import_stmt_test.go index 4dfb8b1a91e2..6f8bbbf02934 100644 --- a/pkg/ccl/importccl/import_stmt_test.go +++ b/pkg/ccl/importccl/import_stmt_test.go @@ -1284,6 +1284,47 @@ func TestImportUserDefinedTypes(t *testing.T) { } } +func TestCreateSequenceAs(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + ctx := context.Background() + baseDir, cleanup := testutils.TempDir(t) + defer cleanup() + tc := testcluster.StartTestCluster( + t, 1, base.TestClusterArgs{ServerArgs: base.TestServerArgs{ExternalIODir: baseDir}}) + defer tc.Stopper().Stop(ctx) + conn := tc.Conns[0] + sqlDB := sqlutils.MakeSQLRunner(conn) + + var data string + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == "GET" { + _, _ = w.Write([]byte(data)) + } + })) + defer srv.Close() + + t.Run("pgdump sequence as", func(t *testing.T) { + + sqlDB.Exec(t, `DROP SEQUENCE IF EXISTS blah`) + + data = ` + CREATE SEQUENCE public.blah + AS integer + START WITH 1 + INCREMENT BY 1 + CACHE 1;` + + // Import sequence from dump format. + importDumpQuery := fmt.Sprintf(`IMPORT PGDUMP ($1)`) + sqlDB.Exec(t, importDumpQuery, srv.URL) + + res := sqlDB.QueryStr(t, `SELECT * FROM blah`) + + sqlDB.Exec(t, `DROP SEQUENCE blah`) + }) +} + func TestImportRowLimit(t *testing.T) { defer leaktest.AfterTest(t)() defer log.Scope(t).Close(t) diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index d17f4f1cbe5b..525aba4b7610 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -6446,6 +6446,7 @@ reference_action: // %Category: DDL // %Text: // CREATE [TEMPORARY | TEMP] SEQUENCE +// [AS ] // [INCREMENT ] // [MINVALUE | NO MINVALUE] // [MAXVALUE | NO MAXVALUE] @@ -6485,7 +6486,7 @@ sequence_option_list: | sequence_option_list sequence_option_elem { $$.val = append($1.seqOpts(), $2.seqOpt()) } sequence_option_elem: - AS typename { return unimplementedWithIssueDetail(sqllex, 25110, $2.typeReference().SQLString()) } + AS typename { $$.val = tree.SequenceOption{Name: tree.SeqOptAs, AsTypename: $2.colType()}} | CYCLE { /* SKIP DOC */ $$.val = tree.SequenceOption{Name: tree.SeqOptCycle} } | NO CYCLE { $$.val = tree.SequenceOption{Name: tree.SeqOptNoCycle} } diff --git a/pkg/sql/sem/tree/create.go b/pkg/sql/sem/tree/create.go index 0d57ad86b2a3..84879eca8229 100644 --- a/pkg/sql/sem/tree/create.go +++ b/pkg/sql/sem/tree/create.go @@ -1392,6 +1392,11 @@ func (node *SequenceOptions) Format(ctx *FmtCtx) { option := &(*node)[i] ctx.WriteByte(' ') switch option.Name { + case SeqOptAs: + ctx.WriteString(option.Name) + ctx.WriteByte(' ') + ctx.WriteString(option.AsTypename.Name()) + // TODO(monicax): Test this. case SeqOptCycle, SeqOptNoCycle: ctx.WriteString(option.Name) case SeqOptCache: @@ -1442,6 +1447,8 @@ func (node *SequenceOptions) Format(ctx *FmtCtx) { type SequenceOption struct { Name string + AsTypename *types.T + IntVal *int64 OptionalWord bool diff --git a/pkg/sql/sequence.go b/pkg/sql/sequence.go index c7e548fbe05b..ad18229d04b0 100644 --- a/pkg/sql/sequence.go +++ b/pkg/sql/sequence.go @@ -29,6 +29,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/privilege" "github.com/cockroachdb/cockroach/pkg/sql/sem/builtins" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/types" "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented" "github.com/cockroachdb/cockroach/pkg/util/log" "github.com/cockroachdb/cockroach/pkg/util/sequence" @@ -275,6 +276,23 @@ func assignSequenceOptions( optionsSeen[option.Name] = true switch option.Name { + case tree.SeqOptAs: + typename := option.AsTypename + switch typename { + case types.Int2: + // TODO(monicax): refactor this + if isAscending { + opts.MinValue = 1 + opts.MaxValue = math.MaxInt16 + opts.Start = opts.MinValue + } else { + opts.MinValue = math.MinInt16 + opts.MaxValue = -1 + opts.Start = opts.MaxValue + } + case types.Int: // this is what integer AND bigint map to + // Do nothing; this is the default. + } case tree.SeqOptCycle: return unimplemented.NewWithIssue(20961, "CYCLE option is not supported")