From efcccce69ccb3bb0d27a9d067370ff5617df0da7 Mon Sep 17 00:00:00 2001 From: Raphael 'kena' Poss Date: Tue, 14 Aug 2018 15:09:05 +0200 Subject: [PATCH 1/3] sql: introduce virtual sequences Suggested/recommended by @BramGruneir. This patch introduces **virtual sequences**, a CockroachDB-specific extension to SQL sequences. Virtual sequences are sequences that do not generate monotonically increasing values and instead produce values like the built-in function `unique_rowid()`. They are intended for use in combination with the PostgreSQL column pseudo-type "SERIAL", where clients expect a sequence object to be created but usually don't really care about the particular values generated by the sequence. Virtual sequences buy us a behavior that's compatible schema-wise with PostgreSQL but without the performance scalability bottleneck of regular sequences. Technically, a virtual sequence is supported by a regular sequence descriptor with just an extra option called "virtual". Therefore it behaves as a database object much alike a regular SQL sequence and can be manipulated with the same DDL (CREATE/DROP/SHOW) etc. and thus appears very much alike a regular SQL sequence to clients -- to ensure they can be used as a substitute to regular SQL sequences without clients noticing. The difference between a virtual sequence and a regular sequence is only to be found in the behavior of the `nextval()` built-in function: with virtual sequences this skips the KV increment operation and instead runs the code of `unique_rowid()`. Release note (sql change): A CockroachDB-specific experimental extension to SQL sequences, called "virtual sequences", is introduced as an experiment to more transparently support PostgreSQL applications using the SERIAL pseudo-type. --- .../sql/bnf/alter_sequence_options_stmt.bnf | 4 +- .../sql/bnf/create_sequence_stmt.bnf | 4 +- docs/generated/sql/bnf/stmt_block.bnf | 1 + .../logictest/testdata/logic_test/sequences | 41 ++ pkg/sql/parser/parse_test.go | 1 + pkg/sql/parser/sql.y | 2 + pkg/sql/sem/tree/create.go | 3 + pkg/sql/sequence.go | 49 ++- pkg/sql/show_create.go | 3 + pkg/sql/sqlbase/structured.pb.go | 410 ++++++++++-------- pkg/sql/sqlbase/structured.proto | 2 + 11 files changed, 312 insertions(+), 208 deletions(-) diff --git a/docs/generated/sql/bnf/alter_sequence_options_stmt.bnf b/docs/generated/sql/bnf/alter_sequence_options_stmt.bnf index 3e5565cbc434..4afb62859919 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' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) )* ) - | 'ALTER' 'SEQUENCE' 'IF' 'EXISTS' sequence_name ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) )* ) + 'ALTER' 'SEQUENCE' sequence_name ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | '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' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | '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 4e72f6730295..24d8aaae9545 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' 'SEQUENCE' sequence_name ( ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) )* ) | ) - | 'CREATE' 'SEQUENCE' 'IF' 'NOT' 'EXISTS' sequence_name ( ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer ) ) )* ) | ) + 'CREATE' 'SEQUENCE' sequence_name ( ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) )* ) | ) + | 'CREATE' 'SEQUENCE' 'IF' 'NOT' 'EXISTS' sequence_name ( ( ( ( 'NO' 'CYCLE' | 'INCREMENT' integer | 'INCREMENT' 'BY' integer | 'MINVALUE' integer | 'NO' 'MINVALUE' | 'MAXVALUE' integer | 'NO' 'MAXVALUE' | 'START' integer | 'START' 'WITH' integer | 'VIRTUAL' ) ) ( ( ( 'NO' 'CYCLE' | '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 1f42e342d813..613fc1214d2b 100644 --- a/docs/generated/sql/bnf/stmt_block.bnf +++ b/docs/generated/sql/bnf/stmt_block.bnf @@ -1768,6 +1768,7 @@ sequence_option_elem ::= | 'NO' 'MAXVALUE' | 'START' signed_iconst64 | 'START' 'WITH' signed_iconst64 + | 'VIRTUAL' opt_asc_desc ::= 'ASC' diff --git a/pkg/sql/logictest/testdata/logic_test/sequences b/pkg/sql/logictest/testdata/logic_test/sequences index 713f39539e48..374fcd7b94d9 100644 --- a/pkg/sql/logictest/testdata/logic_test/sequences +++ b/pkg/sql/logictest/testdata/logic_test/sequences @@ -829,3 +829,44 @@ SELECT last_value FROM priv_test 5 user root + +subtest virtual_sequences + +statement ok +CREATE SEQUENCE sv VIRTUAL + +query T +SELECT create_statement FROM [SHOW CREATE SEQUENCE sv] +---- +CREATE SEQUENCE sv MINVALUE 1 MAXVALUE 9223372036854775807 INCREMENT 1 START 1 VIRTUAL + +statement ok +CREATE TABLE svals(x INT) + +statement ok +BEGIN; + INSERT INTO svals VALUES(nextval('sv')); + INSERT INTO svals VALUES(lastval()); + INSERT INTO svals VALUES(currval('sv')); +END + +# Check that lastval returns the last auto-generated virtual value. +query I +SELECT count(DISTINCT x) FROM svals +---- +1 + +# Check that the KV trace is empty. +statement ok +BEGIN; + SELECT nextval('sv'); -- acquire the lease, so that doesn't go to the KV trace + SET tracing = on; SELECT nextval('sv'); SET tracing = off; + COMMIT + +query T +SELECT message FROM [SHOW KV TRACE FOR SESSION] +---- +rows affected: 1 + +statement ok +DROP SEQUENCE sv diff --git a/pkg/sql/parser/parse_test.go b/pkg/sql/parser/parse_test.go index bfa8c55aaf9b..a5458d64f177 100644 --- a/pkg/sql/parser/parse_test.go +++ b/pkg/sql/parser/parse_test.go @@ -258,6 +258,7 @@ func TestParse(t *testing.T) { {`CREATE SEQUENCE a START WITH 1000`}, {`CREATE SEQUENCE a INCREMENT 5 NO MAXVALUE MINVALUE 1 START 3`}, {`CREATE SEQUENCE a INCREMENT 5 NO CYCLE NO MAXVALUE MINVALUE 1 START 3 CACHE 1`}, + {`CREATE SEQUENCE a VIRTUAL`}, {`CREATE STATISTICS a ON col1 FROM t`}, {`CREATE STATISTICS a ON col1, col2 FROM t`}, diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index 9ef29202f2e3..f8449f9235cc 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -4081,6 +4081,7 @@ numeric_only: // [START [WITH] ] // [CACHE ] // [NO CYCLE] +// [VIRTUAL] // // %SeeAlso: CREATE TABLE create_sequence_stmt: @@ -4134,6 +4135,7 @@ sequence_option_elem: $$.val = tree.SequenceOption{Name: tree.SeqOptStart, IntVal: &x} } | START WITH signed_iconst64 { x := $3.int64() $$.val = tree.SequenceOption{Name: tree.SeqOptStart, IntVal: &x, OptionalWord: true} } +| VIRTUAL { $$.val = tree.SequenceOption{Name: tree.SeqOptVirtual} } // %Help: TRUNCATE - empty one or more tables // %Category: DML diff --git a/pkg/sql/sem/tree/create.go b/pkg/sql/sem/tree/create.go index 33f6a7e5d89a..f88925e46d40 100644 --- a/pkg/sql/sem/tree/create.go +++ b/pkg/sql/sem/tree/create.go @@ -935,6 +935,8 @@ func (node *SequenceOptions) Format(ctx *FmtCtx) { ctx.WriteString("BY ") } ctx.Printf("%d", *option.IntVal) + case SeqOptVirtual: + ctx.WriteString(option.Name) default: panic(fmt.Sprintf("unexpected SequenceOption: %v", option)) } @@ -961,6 +963,7 @@ const ( SeqOptMinValue = "MINVALUE" SeqOptMaxValue = "MAXVALUE" SeqOptStart = "START" + SeqOptVirtual = "VIRTUAL" // Avoid unused warning for constants. _ = SeqOptAs diff --git a/pkg/sql/sequence.go b/pkg/sql/sequence.go index e9e86a7cc93e..cebd25d24318 100644 --- a/pkg/sql/sequence.go +++ b/pkg/sql/sequence.go @@ -23,6 +23,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/roachpb" "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "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/sessiondata" "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" @@ -43,23 +44,28 @@ func (p *planner) IncrementSequence(ctx context.Context, seqName *tree.TableName return 0, err } - seqValueKey := keys.MakeSequenceKey(uint32(descriptor.ID)) - val, err := client.IncrementValRetryable( - ctx, p.txn.DB(), seqValueKey, descriptor.SequenceOpts.Increment) - if err != nil { - switch err.(type) { - case *roachpb.IntegerOverflowError: + seqOpts := descriptor.SequenceOpts + var val int64 + if seqOpts.Virtual { + rowid := builtins.GenerateUniqueInt(p.EvalContext().NodeID) + val = int64(rowid) + } else { + seqValueKey := keys.MakeSequenceKey(uint32(descriptor.ID)) + val, err = client.IncrementValRetryable( + ctx, p.txn.DB(), seqValueKey, descriptor.SequenceOpts.Increment) + if err != nil { + switch err.(type) { + case *roachpb.IntegerOverflowError: + return 0, boundsExceededError(descriptor) + default: + return 0, err + } + } + if val > seqOpts.MaxValue || val < seqOpts.MinValue { return 0, boundsExceededError(descriptor) - default: - return 0, err } } - seqOpts := descriptor.SequenceOpts - if val > seqOpts.MaxValue || val < seqOpts.MinValue { - return 0, boundsExceededError(descriptor) - } - p.ExtendedEvalContext().SessionMutator.RecordLatestSequenceVal(uint32(descriptor.ID), val) return val, nil @@ -80,7 +86,8 @@ func boundsExceededError(descriptor *sqlbase.TableDescriptor) error { } return pgerror.NewErrorf( pgerror.CodeSequenceGeneratorLimitExceeded, - `reached %s value of sequence "%s" (%d)`, word, descriptor.Name, value) + `reached %s value of sequence %q (%d)`, word, + tree.ErrString((*tree.Name)(&descriptor.Name)), value) } // GetLatestValueInSessionForSequence implements the tree.SequenceOperators interface. @@ -96,7 +103,7 @@ func (p *planner) GetLatestValueInSessionForSequence( if !ok { return 0, pgerror.NewErrorf( pgerror.CodeObjectNotInPrerequisiteStateError, - `currval of sequence "%s" is not yet defined in this session`, seqName) + `currval of sequence %q is not yet defined in this session`, tree.ErrString(seqName)) } return val, nil @@ -118,6 +125,16 @@ func (p *planner) SetSequenceValue( return err } + if descriptor.SequenceOpts.Virtual { + // TODO(knz): we currently return an error here, but if/when + // CockroachDB grows to automatically make sequences virtual when + // clients don't expect it, we may need to make this a no-op + // instead. + return pgerror.NewErrorf( + pgerror.CodeObjectNotInPrerequisiteStateError, + `cannot set the value of virtual sequence %q`, tree.ErrString(seqName)) + } + seqValueKey, newVal, err := MakeSequenceKeyVal(descriptor, newVal, isCalled) if err != nil { return err @@ -242,6 +259,8 @@ func assignSequenceOptions( } case tree.SeqOptStart: opts.Start = *option.IntVal + case tree.SeqOptVirtual: + opts.Virtual = true } } diff --git a/pkg/sql/show_create.go b/pkg/sql/show_create.go index 25e9c17ad128..6e8be54bfb4d 100644 --- a/pkg/sql/show_create.go +++ b/pkg/sql/show_create.go @@ -117,6 +117,9 @@ func (p *planner) showCreateSequence( f.Printf(" MAXVALUE %d", opts.MaxValue) f.Printf(" INCREMENT %d", opts.Increment) f.Printf(" START %d", opts.Start) + if opts.Virtual { + f.Printf(" VIRTUAL") + } return f.CloseAndGetString(), nil } diff --git a/pkg/sql/sqlbase/structured.pb.go b/pkg/sql/sqlbase/structured.pb.go index 6e75b382be52..ebd49d37a014 100644 --- a/pkg/sql/sqlbase/structured.pb.go +++ b/pkg/sql/sqlbase/structured.pb.go @@ -1422,6 +1422,8 @@ type TableDescriptor_SequenceOpts struct { MaxValue int64 `protobuf:"varint,3,opt,name=max_value,json=maxValue" json:"max_value"` // Start value of the sequence. Start int64 `protobuf:"varint,4,opt,name=start" json:"start"` + // Whether the sequence is virtual. + Virtual bool `protobuf:"varint,5,opt,name=virtual" json:"virtual"` } func (m *TableDescriptor_SequenceOpts) Reset() { *m = TableDescriptor_SequenceOpts{} } @@ -2760,6 +2762,14 @@ func (m *TableDescriptor_SequenceOpts) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x20 i++ i = encodeVarintStructured(dAtA, i, uint64(m.Start)) + dAtA[i] = 0x28 + i++ + if m.Virtual { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ return i, nil } @@ -3307,6 +3317,7 @@ func (m *TableDescriptor_SequenceOpts) Size() (n int) { n += 1 + sovStructured(uint64(m.MinValue)) n += 1 + sovStructured(uint64(m.MaxValue)) n += 1 + sovStructured(uint64(m.Start)) + n += 2 return n } @@ -7362,6 +7373,26 @@ func (m *TableDescriptor_SequenceOpts) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Virtual", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStructured + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Virtual = bool(v != 0) default: iNdEx = preIndex skippy, err := skipStructured(dAtA[iNdEx:]) @@ -7835,193 +7866,194 @@ var ( func init() { proto.RegisterFile("sql/sqlbase/structured.proto", fileDescriptorStructured) } var fileDescriptorStructured = []byte{ - // 3005 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x59, 0x5f, 0x6f, 0x1b, 0xc7, - 0xb5, 0xd7, 0xf2, 0xff, 0x1e, 0xfe, 0x5b, 0x8d, 0x65, 0x87, 0x66, 0x1c, 0x49, 0x66, 0xe2, 0x5c, - 0xe5, 0x1f, 0xe5, 0xc8, 0xb9, 0xf7, 0x06, 0xb9, 0x17, 0x41, 0x49, 0xee, 0xca, 0x5e, 0x99, 0x22, - 0xe5, 0x25, 0x25, 0xc7, 0x41, 0x5a, 0x62, 0xc9, 0x1d, 0x49, 0x1b, 0x2f, 0x77, 0xe9, 0xdd, 0xa5, - 0x22, 0x7e, 0x83, 0x3c, 0xf6, 0xa1, 0x40, 0x5f, 0x8a, 0x20, 0xc8, 0x6b, 0xbf, 0x40, 0x3f, 0x82, - 0x0b, 0xf4, 0xa1, 0xe8, 0x53, 0x5f, 0x2a, 0xb4, 0x2a, 0x0a, 0xf4, 0x13, 0xf4, 0x21, 0x40, 0x81, - 0x62, 0x66, 0x67, 0x96, 0x4b, 0xfd, 0x0b, 0x65, 0xbf, 0x71, 0xcf, 0x9c, 0xf3, 0x9b, 0x39, 0x67, - 0xce, 0xf9, 0xcd, 0x99, 0x21, 0xdc, 0xf1, 0x5e, 0x58, 0xeb, 0xde, 0x0b, 0xab, 0xaf, 0x7b, 0x78, - 0xdd, 0xf3, 0xdd, 0xf1, 0xc0, 0x1f, 0xbb, 0xd8, 0xa8, 0x8e, 0x5c, 0xc7, 0x77, 0xd0, 0xcd, 0x81, - 0x33, 0x78, 0xee, 0x3a, 0xfa, 0xe0, 0xb0, 0xea, 0xbd, 0xb0, 0xaa, 0x4c, 0xaf, 0x5c, 0x1a, 0xfb, - 0xa6, 0xb5, 0x7e, 0x68, 0x0d, 0xd6, 0x7d, 0x73, 0x88, 0x3d, 0x5f, 0x1f, 0x8e, 0x02, 0x83, 0xf2, - 0x9b, 0x51, 0xb8, 0x91, 0x6b, 0x1e, 0x99, 0x16, 0x3e, 0xc0, 0x6c, 0x70, 0xe9, 0xc0, 0x39, 0x70, - 0xe8, 0xcf, 0x75, 0xf2, 0x2b, 0x90, 0x56, 0x7e, 0x93, 0x06, 0x68, 0x38, 0xd6, 0x78, 0x68, 0x77, - 0x27, 0x23, 0x8c, 0x9e, 0x41, 0xde, 0xc3, 0x43, 0xdd, 0xf6, 0xcd, 0x41, 0xcf, 0x9f, 0x8c, 0x70, - 0x49, 0x58, 0x15, 0xd6, 0x0a, 0x1b, 0xd5, 0xea, 0x85, 0x4b, 0xa9, 0x4e, 0x2d, 0xab, 0x1d, 0x66, - 0x46, 0x3e, 0xea, 0x89, 0x97, 0x27, 0x2b, 0x0b, 0x5a, 0xce, 0x8b, 0xc8, 0x50, 0x19, 0x92, 0xdf, - 0x98, 0x86, 0x7f, 0x58, 0x8a, 0xad, 0x0a, 0x6b, 0x49, 0xa6, 0x12, 0x88, 0x50, 0x05, 0xc4, 0x91, - 0x8b, 0x07, 0xa6, 0x67, 0x3a, 0x76, 0x29, 0x1e, 0x19, 0x9f, 0x8a, 0xd1, 0x7b, 0x20, 0xe9, 0xae, - 0xab, 0x4f, 0x7a, 0x86, 0x39, 0xc4, 0x36, 0x11, 0x79, 0xa5, 0xc4, 0x6a, 0x7c, 0x2d, 0xa9, 0x15, - 0xa9, 0x5c, 0x0e, 0xc5, 0xe8, 0x16, 0xa4, 0x2c, 0x67, 0xa0, 0x5b, 0xb8, 0x94, 0x5c, 0x15, 0xd6, - 0x44, 0x8d, 0x7d, 0xa1, 0x3d, 0xc8, 0x1d, 0x99, 0x9e, 0xd9, 0xb7, 0x70, 0xe0, 0x5c, 0x8a, 0x3a, - 0xf7, 0xd1, 0x4f, 0x3b, 0xb7, 0x17, 0x58, 0x45, 0x7c, 0xcb, 0x1e, 0x4d, 0x45, 0x68, 0x17, 0x0a, - 0xc1, 0xd2, 0x06, 0x8e, 0xed, 0x63, 0xdb, 0xf7, 0x4a, 0xe9, 0x57, 0x09, 0x9b, 0x96, 0xa7, 0x28, - 0x0d, 0x06, 0x82, 0x5a, 0x50, 0xf0, 0xc7, 0x23, 0x0b, 0x4f, 0x61, 0x33, 0xab, 0xf1, 0xb5, 0xec, - 0xc6, 0xdd, 0x9f, 0x84, 0x65, 0x8b, 0xcc, 0x53, 0xf3, 0x10, 0xef, 0x2e, 0xe4, 0x02, 0x3c, 0x4b, - 0xef, 0x63, 0xcb, 0x2b, 0x89, 0xab, 0xf1, 0x35, 0x51, 0xcb, 0x52, 0x59, 0x93, 0x8a, 0x2a, 0xdf, - 0xc5, 0x20, 0x17, 0x5d, 0x12, 0xca, 0x40, 0xa2, 0xde, 0x6e, 0x37, 0xa5, 0x05, 0x94, 0x86, 0xb8, - 0xda, 0xea, 0x4a, 0x02, 0x12, 0x21, 0xb9, 0xd9, 0x6c, 0xd7, 0xba, 0x52, 0x0c, 0x65, 0x21, 0x2d, - 0x2b, 0x0d, 0x75, 0xbb, 0xd6, 0x94, 0xe2, 0x44, 0x55, 0xae, 0x75, 0x15, 0x29, 0x81, 0xf2, 0x20, - 0x76, 0xd5, 0x6d, 0xa5, 0xd3, 0xad, 0x6d, 0xef, 0x48, 0x49, 0x94, 0x83, 0x8c, 0xda, 0xea, 0x2a, - 0xda, 0x5e, 0xad, 0x29, 0xa5, 0x10, 0x40, 0xaa, 0xd3, 0xd5, 0xd4, 0xd6, 0x43, 0x29, 0x4d, 0xa0, - 0xea, 0xcf, 0xba, 0x4a, 0x47, 0xca, 0xa0, 0x22, 0x64, 0x43, 0x9b, 0xee, 0x97, 0x92, 0x88, 0x10, - 0x14, 0x1a, 0xed, 0x66, 0xb3, 0xd6, 0x55, 0x64, 0xa6, 0x0f, 0x64, 0x8a, 0x56, 0x6d, 0x5b, 0x91, - 0xb2, 0x64, 0x35, 0x6d, 0x55, 0x96, 0x72, 0x54, 0xb4, 0xdb, 0x6c, 0x4a, 0x79, 0xf2, 0x6b, 0x77, - 0x57, 0x95, 0xa5, 0x02, 0x81, 0xad, 0x69, 0x5a, 0xed, 0x99, 0x54, 0x24, 0x42, 0xb5, 0xa5, 0x74, - 0x25, 0x89, 0xfc, 0x22, 0x13, 0x48, 0x8b, 0xe4, 0xd7, 0x56, 0xa7, 0xdd, 0x92, 0x10, 0x51, 0xec, - 0xee, 0xee, 0x34, 0x15, 0x69, 0x09, 0x15, 0x01, 0xd4, 0x56, 0x77, 0x63, 0x4f, 0x69, 0x74, 0xdb, - 0x9a, 0xf4, 0x52, 0x40, 0x05, 0x10, 0xdb, 0xaa, 0xcc, 0xbe, 0x7f, 0x2f, 0x54, 0x12, 0x99, 0x1b, - 0xd2, 0x8d, 0xca, 0x01, 0x64, 0x23, 0xc9, 0x40, 0x67, 0x6f, 0xb7, 0x14, 0x69, 0x81, 0x84, 0x82, - 0x38, 0xf9, 0x50, 0xd1, 0x24, 0x81, 0x78, 0xdc, 0xd9, 0xae, 0x35, 0x9b, 0x24, 0x60, 0x31, 0xe2, - 0x71, 0x5d, 0x7d, 0x48, 0x7e, 0xc7, 0xc9, 0xba, 0xeb, 0x6a, 0x57, 0x4a, 0x10, 0x4b, 0x4d, 0xa9, - 0x35, 0xa5, 0x24, 0x5a, 0x02, 0x49, 0x6e, 0xef, 0xd6, 0x9b, 0x4a, 0x6f, 0x47, 0x53, 0x1a, 0x6a, - 0x47, 0x6d, 0xb7, 0xa4, 0xd4, 0x67, 0x89, 0x7f, 0x7e, 0xbf, 0x22, 0x54, 0xfe, 0x15, 0x87, 0x1b, - 0x9b, 0x8e, 0x8b, 0xcd, 0x03, 0xfb, 0x31, 0x9e, 0x68, 0x78, 0x1f, 0xbb, 0xd8, 0x1e, 0x60, 0xb4, - 0x0a, 0x49, 0x5f, 0xef, 0x5b, 0x41, 0x7d, 0xe6, 0xeb, 0x40, 0xb6, 0xfb, 0xc7, 0x93, 0x95, 0x98, - 0x2a, 0x6b, 0xc1, 0x00, 0xba, 0x07, 0x49, 0xd3, 0x36, 0xf0, 0x31, 0x2d, 0xb7, 0x7c, 0xbd, 0xc8, - 0x34, 0xd2, 0x2a, 0x11, 0x12, 0x35, 0x3a, 0x8a, 0x4a, 0x90, 0xb0, 0xf5, 0x21, 0xa6, 0x45, 0x27, - 0xb2, 0xb4, 0xa1, 0x12, 0xf4, 0x18, 0x32, 0x47, 0xba, 0x65, 0x1a, 0xa6, 0x3f, 0x29, 0x25, 0x68, - 0x3a, 0xbf, 0x77, 0x69, 0xde, 0xd9, 0x9e, 0xef, 0xea, 0xa6, 0xed, 0xef, 0x31, 0x03, 0x06, 0x14, - 0x02, 0xa0, 0xfb, 0xb0, 0xe8, 0x1d, 0xea, 0x2e, 0x36, 0x7a, 0x23, 0x17, 0xef, 0x9b, 0xc7, 0x3d, - 0x0b, 0xdb, 0xb4, 0x38, 0x79, 0xa1, 0x17, 0x83, 0xe1, 0x1d, 0x3a, 0xda, 0xc4, 0x36, 0xea, 0x82, - 0xe8, 0xd8, 0x3d, 0x03, 0x5b, 0xd8, 0xe7, 0x85, 0xfa, 0xf1, 0x25, 0xf3, 0x5f, 0x10, 0xa0, 0x6a, - 0x6d, 0xe0, 0x9b, 0x8e, 0xcd, 0xd7, 0xe1, 0xd8, 0x32, 0x05, 0x62, 0xa8, 0xe3, 0x91, 0xa1, 0xfb, - 0x98, 0x15, 0xe9, 0xeb, 0xa0, 0xee, 0x52, 0xa0, 0xca, 0x13, 0x48, 0x05, 0x23, 0x24, 0xf3, 0x5b, - 0xed, 0x5e, 0xad, 0xd1, 0x25, 0x9b, 0xb8, 0x40, 0xf2, 0x40, 0x53, 0x48, 0xf6, 0x36, 0xba, 0x2c, - 0x2b, 0x94, 0x6e, 0x8f, 0xa6, 0x6b, 0x8c, 0x24, 0x3c, 0xf9, 0x92, 0x95, 0xcd, 0xda, 0x6e, 0x93, - 0xa4, 0x46, 0x16, 0xd2, 0x8d, 0x5a, 0xa7, 0x51, 0x93, 0x15, 0x29, 0x51, 0xf9, 0x4b, 0x0c, 0xa4, - 0xa0, 0x9e, 0x65, 0xec, 0x0d, 0x5c, 0x73, 0xe4, 0x3b, 0x6e, 0xb8, 0x59, 0xc2, 0xb9, 0xcd, 0x7a, - 0x17, 0x62, 0xa6, 0xc1, 0xb6, 0xfa, 0x16, 0x91, 0x9f, 0xd2, 0x64, 0xf8, 0xf1, 0x64, 0x25, 0x13, - 0xa0, 0xa8, 0xb2, 0x16, 0x33, 0x0d, 0xf4, 0x7f, 0x90, 0xa0, 0xcc, 0x47, 0xb6, 0xfb, 0x1a, 0x44, - 0x42, 0x8d, 0xd0, 0x2a, 0x64, 0xec, 0xb1, 0x65, 0xd1, 0xbc, 0x23, 0x19, 0x91, 0xe1, 0x81, 0xe0, - 0x52, 0xc2, 0x30, 0x06, 0xde, 0xd7, 0xc7, 0x96, 0xdf, 0xc3, 0xc7, 0x23, 0x97, 0xd1, 0x6f, 0x96, - 0xc9, 0x94, 0xe3, 0x91, 0x8b, 0xee, 0x40, 0xea, 0xd0, 0x34, 0x0c, 0x6c, 0xd3, 0x4d, 0xe5, 0x10, - 0x4c, 0x86, 0x36, 0x60, 0x71, 0xec, 0x61, 0xaf, 0xe7, 0xe1, 0x17, 0x63, 0x12, 0xf1, 0x9e, 0x69, - 0x78, 0x25, 0x58, 0x8d, 0xaf, 0xe5, 0xeb, 0x29, 0x96, 0xdf, 0x45, 0xa2, 0xd0, 0x61, 0xe3, 0xaa, - 0x41, 0x69, 0x6d, 0xe0, 0x0c, 0x47, 0x63, 0x1f, 0x07, 0x93, 0x66, 0x83, 0x49, 0x99, 0x8c, 0x4c, - 0xba, 0x95, 0xc8, 0x64, 0x24, 0x71, 0x2b, 0x91, 0x11, 0x25, 0xd8, 0x4a, 0x64, 0xd2, 0x52, 0xa6, - 0xf2, 0x6d, 0x0c, 0x6e, 0x05, 0x6e, 0x6e, 0xea, 0x43, 0xd3, 0x9a, 0xbc, 0x6e, 0x94, 0x03, 0x14, - 0x16, 0x65, 0xba, 0x22, 0x82, 0xdd, 0x23, 0x66, 0x5e, 0x29, 0x1e, 0x10, 0x6d, 0x20, 0x6b, 0x11, - 0x11, 0xfa, 0x14, 0x80, 0xa9, 0x10, 0x0f, 0x13, 0xd4, 0xc3, 0xdb, 0xa7, 0x27, 0x2b, 0x22, 0xdf, - 0x2e, 0x6f, 0x66, 0xef, 0xc4, 0x40, 0x99, 0xb8, 0xdb, 0x86, 0x45, 0x1e, 0xe3, 0x10, 0x81, 0x06, - 0x3a, 0x5f, 0x7f, 0x9b, 0xad, 0xa9, 0x28, 0x07, 0x0a, 0xdc, 0x7c, 0x06, 0xaa, 0x68, 0xcc, 0x0c, - 0x1a, 0x95, 0xdf, 0xc6, 0x60, 0x49, 0xb5, 0x7d, 0xec, 0x5a, 0x58, 0x3f, 0xc2, 0x91, 0x40, 0x7c, - 0x01, 0xa2, 0x6e, 0x0f, 0xb0, 0xe7, 0x3b, 0xae, 0x57, 0x12, 0xe8, 0xd1, 0xf3, 0xc9, 0x25, 0x19, - 0x73, 0x91, 0x7d, 0xb5, 0xc6, 0x8c, 0xf9, 0x59, 0x1e, 0x82, 0x95, 0x7f, 0x27, 0x40, 0x86, 0x8f, - 0xa2, 0xfb, 0x90, 0xa1, 0x94, 0x45, 0xfc, 0x08, 0xe8, 0xec, 0x26, 0xf3, 0x23, 0xdd, 0x25, 0x72, - 0xba, 0x7e, 0xb2, 0xf3, 0x69, 0xaa, 0xa6, 0x1a, 0xe8, 0xbf, 0x21, 0x43, 0xd9, 0xab, 0x17, 0xee, - 0x46, 0x99, 0x5b, 0x30, 0x7a, 0x8b, 0x32, 0x5d, 0x9a, 0xea, 0xaa, 0x06, 0x6a, 0x5c, 0x44, 0x42, - 0x71, 0x6a, 0xff, 0x06, 0x8f, 0x5c, 0x67, 0x96, 0x86, 0xce, 0xf1, 0x52, 0xe5, 0x1f, 0x71, 0xb8, - 0xb5, 0xa3, 0xbb, 0xbe, 0x49, 0xea, 0xdd, 0xb4, 0x0f, 0x22, 0xf1, 0xba, 0x07, 0x59, 0x7b, 0x3c, - 0x64, 0xbb, 0xe2, 0x31, 0x5f, 0x02, 0xdf, 0xc1, 0x1e, 0x0f, 0x83, 0x80, 0x7b, 0xa8, 0x09, 0x09, - 0xcb, 0xf4, 0xfc, 0x52, 0x8c, 0x46, 0x74, 0xe3, 0x92, 0x88, 0x5e, 0x3c, 0x47, 0xb5, 0x69, 0x7a, - 0x3e, 0xcf, 0x49, 0x82, 0x82, 0xda, 0x90, 0x74, 0x75, 0xfb, 0x00, 0xd3, 0x24, 0xcb, 0x6e, 0x3c, - 0xb8, 0x1e, 0x9c, 0x46, 0x4c, 0x79, 0x2f, 0x46, 0x71, 0xca, 0xbf, 0x16, 0x20, 0x41, 0x66, 0xb9, - 0xa2, 0x0e, 0x6e, 0x41, 0xea, 0x48, 0xb7, 0xc6, 0xd8, 0xa3, 0x3e, 0xe4, 0x34, 0xf6, 0x85, 0x7e, - 0x0e, 0x45, 0x6f, 0xdc, 0x1f, 0x45, 0xa6, 0x62, 0x44, 0xf3, 0xd1, 0xb5, 0x56, 0x15, 0x1e, 0x09, - 0xb3, 0x58, 0xe5, 0xe7, 0x90, 0xa4, 0xeb, 0xbd, 0x62, 0x65, 0xa4, 0xc5, 0x71, 0x7a, 0xf8, 0x78, - 0x60, 0x8d, 0x3d, 0xf3, 0x08, 0xd3, 0xec, 0xc8, 0x69, 0x59, 0xdf, 0x51, 0xb8, 0x08, 0xdd, 0x83, - 0xc2, 0xbe, 0xeb, 0x0c, 0x7b, 0xa6, 0xcd, 0x95, 0xe2, 0x54, 0x29, 0x4f, 0xa4, 0x2a, 0x17, 0x56, - 0xfe, 0x9d, 0x81, 0x22, 0xcd, 0xa0, 0xb9, 0x98, 0xe1, 0x5e, 0x84, 0x19, 0x6e, 0xce, 0x30, 0x43, - 0x98, 0x86, 0x84, 0x18, 0xee, 0x40, 0x6a, 0x6c, 0x9b, 0x2f, 0xc6, 0xc1, 0x9c, 0x21, 0xf9, 0x05, - 0xb2, 0x73, 0xb4, 0x91, 0x38, 0x4f, 0x1b, 0x1f, 0x02, 0x22, 0x35, 0x83, 0x7b, 0x33, 0x8a, 0x49, - 0xaa, 0x28, 0xd1, 0x91, 0xc6, 0xa5, 0x24, 0x93, 0xba, 0x06, 0xc9, 0x3c, 0x02, 0x09, 0x1f, 0xfb, - 0xae, 0xde, 0x8b, 0xd8, 0xa7, 0xa9, 0xfd, 0xf2, 0xe9, 0xc9, 0x4a, 0x41, 0x21, 0x63, 0x17, 0x83, - 0x14, 0x70, 0x64, 0xcc, 0x20, 0x39, 0xb1, 0xc8, 0x30, 0x0c, 0xd3, 0xc5, 0xf4, 0x94, 0x0c, 0xfa, - 0xd8, 0xc2, 0xc6, 0xfd, 0x4b, 0xc9, 0x64, 0x26, 0xec, 0x55, 0x99, 0x1b, 0x6a, 0x52, 0x00, 0x15, - 0x0a, 0x3c, 0xf4, 0x04, 0xb2, 0xfb, 0xc1, 0x41, 0xdd, 0x7b, 0x8e, 0x27, 0x25, 0x91, 0xa6, 0xdb, - 0xfb, 0xf3, 0x1f, 0xe9, 0xbc, 0x3e, 0xf7, 0xc3, 0x21, 0xb4, 0x0b, 0x79, 0x97, 0x0f, 0x1b, 0xbd, - 0xfe, 0x84, 0x9e, 0x3f, 0xaf, 0x02, 0x9a, 0x9b, 0xc2, 0xd4, 0x27, 0xe8, 0x09, 0x80, 0x19, 0xb2, - 0x24, 0x3d, 0xa4, 0xb2, 0x1b, 0x1f, 0x5c, 0x83, 0x4e, 0xf9, 0x4a, 0xa7, 0x20, 0xe8, 0x29, 0x14, - 0xa6, 0x5f, 0x74, 0xa9, 0xb9, 0x57, 0x5c, 0x6a, 0x3e, 0x82, 0x53, 0x9f, 0xa0, 0x2e, 0x2c, 0x91, - 0xe3, 0xd3, 0xf1, 0x4c, 0x1f, 0x47, 0x53, 0x20, 0x4f, 0x53, 0xa0, 0x72, 0x7a, 0xb2, 0x82, 0x1a, - 0x7c, 0xfc, 0xe2, 0x34, 0x40, 0x83, 0x33, 0xe3, 0x41, 0x52, 0xcd, 0x24, 0x2f, 0x41, 0x2c, 0x4c, - 0x93, 0xaa, 0x33, 0x4d, 0xdf, 0x73, 0x49, 0x15, 0x49, 0x6d, 0x82, 0xf4, 0x14, 0x72, 0x33, 0x2c, - 0x53, 0x7c, 0x75, 0x96, 0x99, 0x01, 0x42, 0x0a, 0xeb, 0x8f, 0x24, 0xda, 0x1a, 0x7e, 0x30, 0x67, - 0x82, 0x9e, 0xed, 0x94, 0x2a, 0xcb, 0x20, 0x86, 0x39, 0x4a, 0x5a, 0xfe, 0x5a, 0xa7, 0x21, 0x2d, - 0xd0, 0x0b, 0x92, 0xd2, 0x69, 0x48, 0x42, 0xe5, 0x2e, 0x24, 0xe8, 0xf5, 0x21, 0x0b, 0xe9, 0xcd, - 0xb6, 0xf6, 0xb4, 0xa6, 0xc9, 0x41, 0xb3, 0xa8, 0xb6, 0xf6, 0x14, 0xad, 0xab, 0xc8, 0x92, 0x50, - 0xf9, 0x21, 0x01, 0x68, 0x3a, 0xc5, 0xf6, 0xd8, 0xd7, 0x29, 0x58, 0x0d, 0x52, 0x41, 0xf4, 0x28, - 0x09, 0x65, 0x37, 0xfe, 0xeb, 0xca, 0x16, 0x6e, 0x0a, 0xf0, 0x68, 0x41, 0x63, 0x86, 0xe8, 0xf3, - 0xe8, 0xcd, 0x20, 0xbb, 0xf1, 0xee, 0x7c, 0x4e, 0x3e, 0x5a, 0xe0, 0x57, 0x86, 0xc7, 0x90, 0xf4, - 0x7c, 0xd2, 0x3f, 0xc7, 0x69, 0x90, 0xd6, 0x2f, 0xb1, 0x3f, 0xbf, 0xf8, 0x6a, 0x87, 0x98, 0xf1, - 0xd3, 0x86, 0x62, 0xa0, 0xa7, 0x20, 0x86, 0xbc, 0xc0, 0xae, 0x19, 0x0f, 0xe6, 0x07, 0x0c, 0x83, - 0xcc, 0x5b, 0x8c, 0x10, 0x0b, 0xd5, 0x20, 0x3b, 0x64, 0x6a, 0xd3, 0x06, 0x69, 0x95, 0x51, 0x33, - 0x70, 0x04, 0x4a, 0xd1, 0x91, 0x2f, 0x0d, 0xb8, 0x91, 0x6a, 0x90, 0x7e, 0xd7, 0x75, 0x2c, 0xab, - 0xaf, 0x0f, 0x9e, 0xd3, 0xbb, 0x42, 0xd8, 0xef, 0x72, 0x69, 0xe5, 0x67, 0x90, 0xa4, 0x3e, 0x91, - 0x8d, 0xdc, 0x6d, 0x3d, 0x6e, 0xb5, 0x9f, 0x92, 0xae, 0xbf, 0x08, 0x59, 0x59, 0x69, 0x2a, 0x5d, - 0xa5, 0xd7, 0x6e, 0x35, 0x9f, 0x49, 0x02, 0xba, 0x0d, 0x37, 0x99, 0xa0, 0xd6, 0x92, 0x7b, 0x4f, - 0x35, 0x95, 0x0f, 0xc5, 0x2a, 0x6b, 0xd1, 0x4c, 0x99, 0xde, 0x26, 0x49, 0xce, 0xc8, 0xb2, 0x24, - 0xd0, 0x9c, 0xd1, 0xda, 0x3b, 0x52, 0xac, 0x9e, 0x03, 0x30, 0xc2, 0x08, 0x6c, 0x25, 0x32, 0x29, - 0x29, 0x5d, 0xf9, 0x43, 0x09, 0x8a, 0xb4, 0x47, 0x9a, 0xeb, 0x90, 0x5a, 0xa5, 0x87, 0x54, 0xd0, - 0xf0, 0x48, 0x33, 0x87, 0x54, 0x8c, 0x9d, 0x4f, 0x0f, 0x40, 0x1c, 0xe9, 0x2e, 0xb6, 0x7d, 0x12, - 0xb2, 0xc4, 0x4c, 0x9f, 0x9b, 0xd9, 0xa1, 0x03, 0xa1, 0x7a, 0x26, 0x50, 0x54, 0x89, 0x51, 0xfa, - 0x08, 0xbb, 0xf4, 0xe9, 0x26, 0x88, 0xf2, 0x6d, 0x76, 0xd7, 0x5c, 0x9c, 0xae, 0x6a, 0x2f, 0x50, - 0xd0, 0xb8, 0x26, 0x7a, 0x1b, 0x60, 0x3c, 0xea, 0x71, 0xbb, 0xe8, 0x55, 0x40, 0x1c, 0x8f, 0x98, - 0x36, 0xda, 0x81, 0xc5, 0xa1, 0x63, 0x98, 0xfb, 0xe6, 0x20, 0xd8, 0x47, 0xdf, 0x1c, 0x06, 0xb7, - 0xb6, 0xec, 0xc6, 0x5b, 0x91, 0x24, 0x19, 0xfb, 0xa6, 0x55, 0x3d, 0xb4, 0x06, 0xd5, 0x2e, 0x7f, - 0x0f, 0x63, 0x50, 0x52, 0xd4, 0x9a, 0x0c, 0xa2, 0x87, 0x90, 0xe6, 0xed, 0x59, 0xf0, 0x96, 0x32, - 0x6f, 0xfd, 0x30, 0x44, 0x6e, 0x8d, 0x36, 0xa1, 0x60, 0xe3, 0xe3, 0x68, 0x0b, 0x2e, 0xce, 0x64, - 0x58, 0xae, 0x85, 0x8f, 0x2f, 0xee, 0xbf, 0x73, 0xf6, 0x74, 0xc4, 0x40, 0x4f, 0x20, 0x3f, 0x72, - 0xcd, 0xa1, 0xee, 0x4e, 0x7a, 0x41, 0x51, 0xc2, 0x75, 0x8a, 0x32, 0xe4, 0xb0, 0x00, 0x82, 0x8e, - 0xa2, 0x4d, 0x08, 0x3a, 0x5e, 0xec, 0x95, 0xb2, 0xd4, 0xc7, 0xeb, 0x81, 0x71, 0x63, 0x54, 0x87, - 0x3c, 0x75, 0x31, 0x6c, 0xb5, 0x73, 0xd4, 0xc3, 0x65, 0xe6, 0x61, 0x96, 0x78, 0x78, 0x41, 0xbb, - 0x9d, 0xb5, 0x43, 0xb9, 0x81, 0xb6, 0x00, 0xc2, 0x77, 0x48, 0x72, 0x7c, 0x5c, 0x75, 0x3a, 0xef, - 0x70, 0xc5, 0xe9, 0x92, 0xb4, 0x88, 0x35, 0xda, 0x06, 0x91, 0x17, 0x67, 0x70, 0x6e, 0x64, 0x2f, - 0x7d, 0x91, 0x38, 0x4f, 0x15, 0x3c, 0xb9, 0x42, 0x04, 0xd4, 0x82, 0xa4, 0x85, 0x75, 0x0f, 0xb3, - 0xc3, 0xe3, 0xd3, 0x4b, 0xa0, 0xce, 0x94, 0x57, 0xb5, 0x33, 0x38, 0xc4, 0x43, 0xbd, 0x71, 0x48, - 0x1a, 0xd1, 0x26, 0xb1, 0xd7, 0x02, 0x18, 0xd4, 0x02, 0x89, 0x86, 0x2b, 0xca, 0x3a, 0x12, 0x8d, - 0xd8, 0x3b, 0x2c, 0x62, 0x05, 0x12, 0xb1, 0x4b, 0x99, 0x87, 0xe6, 0xd3, 0xf6, 0x94, 0x7d, 0xfe, - 0x1f, 0x0a, 0xfb, 0x8e, 0x3b, 0xd4, 0xfd, 0xb0, 0x4a, 0x16, 0xa7, 0xed, 0xe5, 0x8f, 0x27, 0x2b, - 0xf9, 0x4d, 0x3a, 0xca, 0x2b, 0x2b, 0xbf, 0x1f, 0xfd, 0x44, 0x8f, 0x38, 0x49, 0xdf, 0xa0, 0x9c, - 0xfa, 0xe1, 0xbc, 0xde, 0x9d, 0x67, 0xe8, 0x16, 0xa4, 0x06, 0x87, 0x78, 0xf0, 0xdc, 0x2b, 0x2d, - 0xd1, 0x98, 0xff, 0xcf, 0x9c, 0x50, 0x0d, 0x62, 0x34, 0x7d, 0x1a, 0xd2, 0x18, 0x0a, 0xfa, 0x0a, - 0x0a, 0x06, 0x91, 0x98, 0xf6, 0x01, 0x6b, 0x5f, 0x6f, 0x52, 0xdc, 0xf5, 0x39, 0x71, 0x49, 0x6b, - 0xab, 0xda, 0xfb, 0x0e, 0xef, 0x5c, 0x38, 0x58, 0xd0, 0xf2, 0xb6, 0x21, 0xb3, 0x4f, 0xae, 0xe2, - 0x26, 0xf6, 0x4a, 0xb7, 0x28, 0xee, 0xd5, 0xcf, 0xbb, 0x67, 0x6f, 0xff, 0x9c, 0xe2, 0x39, 0x48, - 0x58, 0xe8, 0x54, 0x30, 0x21, 0x9b, 0xfa, 0xc6, 0xf9, 0x42, 0xe7, 0xb7, 0xff, 0x99, 0x97, 0x00, - 0x5a, 0xe8, 0xec, 0xcb, 0x20, 0x84, 0x77, 0x64, 0xe2, 0x6f, 0x7a, 0x2f, 0xc6, 0xd8, 0x9d, 0x94, - 0x4a, 0x11, 0x72, 0x16, 0x89, 0xfc, 0x09, 0x11, 0xa3, 0x8f, 0x41, 0x34, 0xf0, 0x08, 0xdb, 0x86, - 0xd7, 0xb6, 0x4b, 0xb7, 0x69, 0x6b, 0x74, 0x83, 0xf4, 0xeb, 0x32, 0x17, 0x32, 0xf2, 0x9d, 0x6a, - 0xa1, 0xaf, 0x21, 0x17, 0x7c, 0x60, 0xa3, 0x6d, 0xd7, 0x27, 0xa5, 0x32, 0x75, 0xfa, 0xfe, 0x9c, - 0xc1, 0x9c, 0xf6, 0x81, 0x4b, 0xdc, 0x1f, 0x39, 0x82, 0xa6, 0xcd, 0x60, 0xa3, 0xaf, 0x20, 0xc7, - 0xb3, 0x7b, 0xcb, 0xe9, 0x7b, 0xa5, 0x37, 0xaf, 0xbc, 0xc1, 0x9e, 0x9d, 0x6b, 0x7b, 0x6a, 0xca, - 0x79, 0x2b, 0x8a, 0x86, 0xbe, 0x80, 0x7c, 0xf8, 0xec, 0xe3, 0x8c, 0x7c, 0xaf, 0x74, 0x87, 0x16, - 0xe6, 0x83, 0x79, 0x53, 0x97, 0xd9, 0xb6, 0x47, 0xbe, 0xa7, 0xe5, 0xbc, 0xc8, 0x17, 0xba, 0x0b, - 0xa2, 0xe1, 0x3a, 0xa3, 0xe0, 0xfc, 0x78, 0x6b, 0x55, 0x58, 0x8b, 0xf3, 0x6d, 0x26, 0x62, 0x7a, - 0x30, 0xf4, 0xa0, 0xe0, 0xe2, 0x91, 0xa5, 0x0f, 0xf0, 0x90, 0x1c, 0x7f, 0xce, 0x7e, 0x69, 0x99, - 0xce, 0xbe, 0x31, 0x77, 0x20, 0x43, 0x63, 0x9e, 0x98, 0x11, 0xbc, 0xf6, 0x3e, 0xda, 0x05, 0xd0, - 0xc7, 0x86, 0xe9, 0xf7, 0x86, 0x8e, 0x81, 0x4b, 0x2b, 0xb4, 0x2a, 0xe7, 0xdd, 0xa5, 0x1a, 0x31, - 0xdc, 0x76, 0x0c, 0x1c, 0xbe, 0xa4, 0x70, 0x41, 0xf9, 0x07, 0x01, 0x16, 0xcf, 0x51, 0x12, 0xfa, - 0x05, 0xa4, 0x6d, 0xc7, 0x88, 0xbc, 0xa8, 0x28, 0x6c, 0x77, 0x53, 0x2d, 0xc7, 0x08, 0x1e, 0x54, - 0x1e, 0x1c, 0x98, 0xfe, 0xe1, 0xb8, 0x5f, 0x1d, 0x38, 0xc3, 0xf5, 0x70, 0x15, 0x46, 0x7f, 0xfa, - 0x7b, 0x7d, 0xf4, 0xfc, 0x60, 0x9d, 0xfe, 0x1a, 0xf5, 0xab, 0x81, 0x99, 0x96, 0x22, 0xa8, 0xaa, - 0x81, 0x3e, 0x82, 0x22, 0x3e, 0x1e, 0x99, 0x6e, 0xe4, 0x58, 0x8e, 0x45, 0xc2, 0x5a, 0x98, 0x0e, - 0x92, 0xe0, 0x96, 0xff, 0x24, 0x40, 0xf1, 0x0c, 0x1d, 0x90, 0x36, 0x85, 0xbe, 0xd6, 0xcd, 0xb4, - 0x29, 0x44, 0x12, 0x36, 0x30, 0xb1, 0x2b, 0x9f, 0xa4, 0xe3, 0xaf, 0xfb, 0x24, 0x3d, 0x7b, 0x39, - 0x4e, 0xce, 0x7f, 0x39, 0xde, 0x4a, 0x64, 0x12, 0x52, 0xb2, 0xfc, 0x0c, 0x32, 0x9c, 0x8a, 0x66, - 0xfb, 0x26, 0x61, 0xce, 0xbe, 0xe9, 0x52, 0x3f, 0xcb, 0xdf, 0x09, 0x20, 0x46, 0xdf, 0xfa, 0x63, - 0x21, 0xea, 0xc5, 0x6d, 0xdb, 0x2b, 0xbe, 0x87, 0xcd, 0x46, 0x20, 0x3e, 0x7f, 0x04, 0xca, 0x47, - 0x90, 0x8d, 0x54, 0xf3, 0xd9, 0x5e, 0x5b, 0x78, 0x85, 0x5e, 0xfb, 0x1d, 0x48, 0x7d, 0xed, 0xf4, - 0xb9, 0x03, 0xf1, 0x7a, 0x9e, 0x59, 0x27, 0xb7, 0x9c, 0xbe, 0x2a, 0x6b, 0xc9, 0xaf, 0x9d, 0xbe, - 0x6a, 0x94, 0x7f, 0x25, 0x40, 0x2e, 0x5a, 0xe7, 0xa8, 0x02, 0xa2, 0x69, 0x0f, 0x5c, 0x5a, 0x64, - 0x74, 0x5e, 0x9e, 0x82, 0x53, 0x31, 0xa9, 0xfe, 0xa1, 0x69, 0xf7, 0xe8, 0x1b, 0xd5, 0x4c, 0x9a, - 0x66, 0x86, 0xa6, 0xbd, 0x47, 0xa4, 0x54, 0x45, 0x3f, 0x66, 0x2a, 0xf1, 0x19, 0x15, 0xfd, 0x38, - 0x50, 0x29, 0xd3, 0x03, 0xd5, 0xf5, 0x69, 0x5b, 0x1c, 0x8f, 0x1c, 0x91, 0xae, 0x5f, 0x3e, 0x84, - 0x6c, 0xa4, 0xfe, 0xe7, 0xd8, 0xb0, 0xff, 0x85, 0x44, 0x58, 0x34, 0x73, 0xf6, 0xb2, 0xd4, 0xa0, - 0xf2, 0x2e, 0xbf, 0x70, 0x00, 0xa4, 0x76, 0x76, 0xeb, 0x4d, 0xb5, 0x71, 0xe1, 0x65, 0x81, 0x5c, - 0x2b, 0x42, 0xd2, 0x20, 0x17, 0x4b, 0x59, 0xed, 0xd4, 0xea, 0x4d, 0x85, 0x5c, 0x33, 0xf3, 0x20, - 0x6a, 0x4a, 0x4d, 0xa6, 0xb7, 0x10, 0x49, 0xf8, 0x2c, 0xf1, 0xed, 0xf7, 0x2b, 0xc2, 0x56, 0x22, - 0x83, 0xa4, 0x1b, 0x95, 0x1f, 0x04, 0x40, 0xb2, 0xee, 0xeb, 0xa4, 0x84, 0xae, 0x71, 0xa3, 0x88, - 0x5d, 0xe1, 0xe9, 0x6c, 0x03, 0x18, 0x7f, 0x9d, 0x06, 0x30, 0x58, 0x6a, 0xe5, 0x3b, 0x01, 0x20, - 0xb2, 0xb8, 0xcf, 0xa3, 0xff, 0x84, 0x5d, 0xde, 0xeb, 0x9e, 0xa1, 0x54, 0x72, 0x9b, 0x0d, 0xfe, - 0x27, 0x7b, 0x08, 0x19, 0x83, 0xb9, 0xcc, 0xb6, 0xe3, 0xd2, 0xa6, 0xf2, 0x5c, 0x64, 0x1e, 0x91, - 0x13, 0x84, 0x49, 0xeb, 0x69, 0x48, 0x8e, 0x6d, 0xd3, 0xb1, 0xdf, 0xff, 0x04, 0xd0, 0x79, 0xfa, - 0x21, 0x61, 0xa7, 0xbf, 0x75, 0x1f, 0x1b, 0xc1, 0x1d, 0x71, 0xd7, 0x3e, 0x0a, 0x05, 0x42, 0xfd, - 0xee, 0xcb, 0xbf, 0x2d, 0x2f, 0xbc, 0x3c, 0x5d, 0x16, 0xfe, 0x78, 0xba, 0x2c, 0xfc, 0xf9, 0x74, - 0x59, 0xf8, 0xeb, 0xe9, 0xb2, 0xf0, 0xcb, 0xbf, 0x2f, 0x2f, 0x7c, 0x99, 0x66, 0x0b, 0xf8, 0x4f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x39, 0xdc, 0xa3, 0x4c, 0x2e, 0x20, 0x00, 0x00, + // 3018 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x59, 0xcd, 0x73, 0x1b, 0xc7, + 0xb1, 0xe7, 0xe2, 0x7b, 0x1b, 0x5f, 0xcb, 0x11, 0x25, 0x43, 0xb0, 0x4c, 0x52, 0xb0, 0xe5, 0x47, + 0x7f, 0x81, 0x32, 0xe5, 0xf7, 0x9e, 0xcb, 0xef, 0x95, 0x2b, 0x00, 0x76, 0x29, 0x2d, 0x05, 0x02, + 0xd4, 0x02, 0xa4, 0x2c, 0x97, 0x13, 0xd4, 0x02, 0x3b, 0x24, 0xd7, 0x5a, 0xec, 0x42, 0xbb, 0x0b, + 0x9a, 0xf8, 0x0f, 0x7c, 0xcc, 0x2d, 0x97, 0x94, 0xcb, 0xe5, 0x6b, 0xae, 0x39, 0xe4, 0x4f, 0x50, + 0x6e, 0xa9, 0x9c, 0x72, 0x09, 0x2b, 0x61, 0x2a, 0x55, 0x39, 0xe4, 0x9c, 0x83, 0xab, 0x52, 0x95, + 0x9a, 0xd9, 0x99, 0xc5, 0x82, 0x5f, 0x06, 0xa5, 0x1b, 0xb6, 0xa7, 0xfb, 0x37, 0xd3, 0x3d, 0xdd, + 0xbf, 0xe9, 0x19, 0xc0, 0x1d, 0xef, 0x85, 0xb5, 0xee, 0xbd, 0xb0, 0xfa, 0xba, 0x87, 0xd7, 0x3d, + 0xdf, 0x1d, 0x0f, 0xfc, 0xb1, 0x8b, 0x8d, 0xea, 0xc8, 0x75, 0x7c, 0x07, 0xdd, 0x1c, 0x38, 0x83, + 0xe7, 0xae, 0xa3, 0x0f, 0x0e, 0xab, 0xde, 0x0b, 0xab, 0xca, 0xf4, 0xca, 0xa5, 0xb1, 0x6f, 0x5a, + 0xeb, 0x87, 0xd6, 0x60, 0xdd, 0x37, 0x87, 0xd8, 0xf3, 0xf5, 0xe1, 0x28, 0x30, 0x28, 0xbf, 0x19, + 0x85, 0x1b, 0xb9, 0xe6, 0x91, 0x69, 0xe1, 0x03, 0xcc, 0x06, 0x97, 0x0e, 0x9c, 0x03, 0x87, 0xfe, + 0x5c, 0x27, 0xbf, 0x02, 0x69, 0xe5, 0xd7, 0x69, 0x80, 0x86, 0x63, 0x8d, 0x87, 0x76, 0x77, 0x32, + 0xc2, 0xe8, 0x19, 0xe4, 0x3d, 0x3c, 0xd4, 0x6d, 0xdf, 0x1c, 0xf4, 0xfc, 0xc9, 0x08, 0x97, 0x84, + 0x55, 0x61, 0xad, 0xb0, 0x51, 0xad, 0x5e, 0xb8, 0x94, 0xea, 0xd4, 0xb2, 0xda, 0x61, 0x66, 0xe4, + 0xa3, 0x9e, 0x78, 0x79, 0xb2, 0xb2, 0xa0, 0xe5, 0xbc, 0x88, 0x0c, 0x95, 0x21, 0xf9, 0x8d, 0x69, + 0xf8, 0x87, 0xa5, 0xd8, 0xaa, 0xb0, 0x96, 0x64, 0x2a, 0x81, 0x08, 0x55, 0x40, 0x1c, 0xb9, 0x78, + 0x60, 0x7a, 0xa6, 0x63, 0x97, 0xe2, 0x91, 0xf1, 0xa9, 0x18, 0xbd, 0x07, 0x92, 0xee, 0xba, 0xfa, + 0xa4, 0x67, 0x98, 0x43, 0x6c, 0x13, 0x91, 0x57, 0x4a, 0xac, 0xc6, 0xd7, 0x92, 0x5a, 0x91, 0xca, + 0xe5, 0x50, 0x8c, 0x6e, 0x41, 0xca, 0x72, 0x06, 0xba, 0x85, 0x4b, 0xc9, 0x55, 0x61, 0x4d, 0xd4, + 0xd8, 0x17, 0xda, 0x83, 0xdc, 0x91, 0xe9, 0x99, 0x7d, 0x0b, 0x07, 0xce, 0xa5, 0xa8, 0x73, 0x1f, + 0xfd, 0xb4, 0x73, 0x7b, 0x81, 0x55, 0xc4, 0xb7, 0xec, 0xd1, 0x54, 0x84, 0x76, 0xa1, 0x10, 0x2c, + 0x6d, 0xe0, 0xd8, 0x3e, 0xb6, 0x7d, 0xaf, 0x94, 0x7e, 0x95, 0xb0, 0x69, 0x79, 0x8a, 0xd2, 0x60, + 0x20, 0xa8, 0x05, 0x05, 0x7f, 0x3c, 0xb2, 0xf0, 0x14, 0x36, 0xb3, 0x1a, 0x5f, 0xcb, 0x6e, 0xdc, + 0xfd, 0x49, 0x58, 0xb6, 0xc8, 0x3c, 0x35, 0x0f, 0xf1, 0xee, 0x42, 0x2e, 0xc0, 0xb3, 0xf4, 0x3e, + 0xb6, 0xbc, 0x92, 0xb8, 0x1a, 0x5f, 0x13, 0xb5, 0x2c, 0x95, 0x35, 0xa9, 0xa8, 0xf2, 0x5d, 0x0c, + 0x72, 0xd1, 0x25, 0xa1, 0x0c, 0x24, 0xea, 0xed, 0x76, 0x53, 0x5a, 0x40, 0x69, 0x88, 0xab, 0xad, + 0xae, 0x24, 0x20, 0x11, 0x92, 0x9b, 0xcd, 0x76, 0xad, 0x2b, 0xc5, 0x50, 0x16, 0xd2, 0xb2, 0xd2, + 0x50, 0xb7, 0x6b, 0x4d, 0x29, 0x4e, 0x54, 0xe5, 0x5a, 0x57, 0x91, 0x12, 0x28, 0x0f, 0x62, 0x57, + 0xdd, 0x56, 0x3a, 0xdd, 0xda, 0xf6, 0x8e, 0x94, 0x44, 0x39, 0xc8, 0xa8, 0xad, 0xae, 0xa2, 0xed, + 0xd5, 0x9a, 0x52, 0x0a, 0x01, 0xa4, 0x3a, 0x5d, 0x4d, 0x6d, 0x3d, 0x94, 0xd2, 0x04, 0xaa, 0xfe, + 0xac, 0xab, 0x74, 0xa4, 0x0c, 0x2a, 0x42, 0x36, 0xb4, 0xe9, 0x7e, 0x29, 0x89, 0x08, 0x41, 0xa1, + 0xd1, 0x6e, 0x36, 0x6b, 0x5d, 0x45, 0x66, 0xfa, 0x40, 0xa6, 0x68, 0xd5, 0xb6, 0x15, 0x29, 0x4b, + 0x56, 0xd3, 0x56, 0x65, 0x29, 0x47, 0x45, 0xbb, 0xcd, 0xa6, 0x94, 0x27, 0xbf, 0x76, 0x77, 0x55, + 0x59, 0x2a, 0x10, 0xd8, 0x9a, 0xa6, 0xd5, 0x9e, 0x49, 0x45, 0x22, 0x54, 0x5b, 0x4a, 0x57, 0x92, + 0xc8, 0x2f, 0x32, 0x81, 0xb4, 0x48, 0x7e, 0x6d, 0x75, 0xda, 0x2d, 0x09, 0x11, 0xc5, 0xee, 0xee, + 0x4e, 0x53, 0x91, 0x96, 0x50, 0x11, 0x40, 0x6d, 0x75, 0x37, 0xf6, 0x94, 0x46, 0xb7, 0xad, 0x49, + 0x2f, 0x05, 0x54, 0x00, 0xb1, 0xad, 0xca, 0xec, 0xfb, 0xf7, 0x42, 0x25, 0x91, 0xb9, 0x21, 0xdd, + 0xa8, 0x1c, 0x40, 0x36, 0x92, 0x0c, 0x74, 0xf6, 0x76, 0x4b, 0x91, 0x16, 0x48, 0x28, 0x88, 0x93, + 0x0f, 0x15, 0x4d, 0x12, 0x88, 0xc7, 0x9d, 0xed, 0x5a, 0xb3, 0x49, 0x02, 0x16, 0x23, 0x1e, 0xd7, + 0xd5, 0x87, 0xe4, 0x77, 0x9c, 0xac, 0xbb, 0xae, 0x76, 0xa5, 0x04, 0xb1, 0xd4, 0x94, 0x5a, 0x53, + 0x4a, 0xa2, 0x25, 0x90, 0xe4, 0xf6, 0x6e, 0xbd, 0xa9, 0xf4, 0x76, 0x34, 0xa5, 0xa1, 0x76, 0xd4, + 0x76, 0x4b, 0x4a, 0x7d, 0x96, 0xf8, 0xc7, 0xf7, 0x2b, 0x42, 0xe5, 0x5f, 0x71, 0xb8, 0xb1, 0xe9, + 0xb8, 0xd8, 0x3c, 0xb0, 0x1f, 0xe3, 0x89, 0x86, 0xf7, 0xb1, 0x8b, 0xed, 0x01, 0x46, 0xab, 0x90, + 0xf4, 0xf5, 0xbe, 0x15, 0xd4, 0x67, 0xbe, 0x0e, 0x64, 0xbb, 0x7f, 0x3c, 0x59, 0x89, 0xa9, 0xb2, + 0x16, 0x0c, 0xa0, 0x7b, 0x90, 0x34, 0x6d, 0x03, 0x1f, 0xd3, 0x72, 0xcb, 0xd7, 0x8b, 0x4c, 0x23, + 0xad, 0x12, 0x21, 0x51, 0xa3, 0xa3, 0xa8, 0x04, 0x09, 0x5b, 0x1f, 0x62, 0x5a, 0x74, 0x22, 0x4b, + 0x1b, 0x2a, 0x41, 0x8f, 0x21, 0x73, 0xa4, 0x5b, 0xa6, 0x61, 0xfa, 0x93, 0x52, 0x82, 0xa6, 0xf3, + 0x7b, 0x97, 0xe6, 0x9d, 0xed, 0xf9, 0xae, 0x6e, 0xda, 0xfe, 0x1e, 0x33, 0x60, 0x40, 0x21, 0x00, + 0xba, 0x0f, 0x8b, 0xde, 0xa1, 0xee, 0x62, 0xa3, 0x37, 0x72, 0xf1, 0xbe, 0x79, 0xdc, 0xb3, 0xb0, + 0x4d, 0x8b, 0x93, 0x17, 0x7a, 0x31, 0x18, 0xde, 0xa1, 0xa3, 0x4d, 0x6c, 0xa3, 0x2e, 0x88, 0x8e, + 0xdd, 0x33, 0xb0, 0x85, 0x7d, 0x5e, 0xa8, 0x1f, 0x5f, 0x32, 0xff, 0x05, 0x01, 0xaa, 0xd6, 0x06, + 0xbe, 0xe9, 0xd8, 0x7c, 0x1d, 0x8e, 0x2d, 0x53, 0x20, 0x86, 0x3a, 0x1e, 0x19, 0xba, 0x8f, 0x59, + 0x91, 0xbe, 0x0e, 0xea, 0x2e, 0x05, 0xaa, 0x3c, 0x81, 0x54, 0x30, 0x42, 0x32, 0xbf, 0xd5, 0xee, + 0xd5, 0x1a, 0x5d, 0xb2, 0x89, 0x0b, 0x24, 0x0f, 0x34, 0x85, 0x64, 0x6f, 0xa3, 0xcb, 0xb2, 0x42, + 0xe9, 0xf6, 0x68, 0xba, 0xc6, 0x48, 0xc2, 0x93, 0x2f, 0x59, 0xd9, 0xac, 0xed, 0x36, 0x49, 0x6a, + 0x64, 0x21, 0xdd, 0xa8, 0x75, 0x1a, 0x35, 0x59, 0x91, 0x12, 0x95, 0x3f, 0xc7, 0x40, 0x0a, 0xea, + 0x59, 0xc6, 0xde, 0xc0, 0x35, 0x47, 0xbe, 0xe3, 0x86, 0x9b, 0x25, 0x9c, 0xdb, 0xac, 0x77, 0x21, + 0x66, 0x1a, 0x6c, 0xab, 0x6f, 0x11, 0xf9, 0x29, 0x4d, 0x86, 0x1f, 0x4f, 0x56, 0x32, 0x01, 0x8a, + 0x2a, 0x6b, 0x31, 0xd3, 0x40, 0xff, 0x07, 0x09, 0xca, 0x7c, 0x64, 0xbb, 0xaf, 0x41, 0x24, 0xd4, + 0x08, 0xad, 0x42, 0xc6, 0x1e, 0x5b, 0x16, 0xcd, 0x3b, 0x92, 0x11, 0x19, 0x1e, 0x08, 0x2e, 0x25, + 0x0c, 0x63, 0xe0, 0x7d, 0x7d, 0x6c, 0xf9, 0x3d, 0x7c, 0x3c, 0x72, 0x19, 0xfd, 0x66, 0x99, 0x4c, + 0x39, 0x1e, 0xb9, 0xe8, 0x0e, 0xa4, 0x0e, 0x4d, 0xc3, 0xc0, 0x36, 0xdd, 0x54, 0x0e, 0xc1, 0x64, + 0x68, 0x03, 0x16, 0xc7, 0x1e, 0xf6, 0x7a, 0x1e, 0x7e, 0x31, 0x26, 0x11, 0xef, 0x99, 0x86, 0x57, + 0x82, 0xd5, 0xf8, 0x5a, 0xbe, 0x9e, 0x62, 0xf9, 0x5d, 0x24, 0x0a, 0x1d, 0x36, 0xae, 0x1a, 0x94, + 0xd6, 0x06, 0xce, 0x70, 0x34, 0xf6, 0x71, 0x30, 0x69, 0x36, 0x98, 0x94, 0xc9, 0xc8, 0xa4, 0x5b, + 0x89, 0x4c, 0x46, 0x12, 0xb7, 0x12, 0x19, 0x51, 0x82, 0xad, 0x44, 0x26, 0x2d, 0x65, 0x2a, 0xdf, + 0xc6, 0xe0, 0x56, 0xe0, 0xe6, 0xa6, 0x3e, 0x34, 0xad, 0xc9, 0xeb, 0x46, 0x39, 0x40, 0x61, 0x51, + 0xa6, 0x2b, 0x22, 0xd8, 0x3d, 0x62, 0xe6, 0x95, 0xe2, 0x01, 0xd1, 0x06, 0xb2, 0x16, 0x11, 0xa1, + 0x4f, 0x01, 0x98, 0x0a, 0xf1, 0x30, 0x41, 0x3d, 0xbc, 0x7d, 0x7a, 0xb2, 0x22, 0xf2, 0xed, 0xf2, + 0x66, 0xf6, 0x4e, 0x0c, 0x94, 0x89, 0xbb, 0x6d, 0x58, 0xe4, 0x31, 0x0e, 0x11, 0x68, 0xa0, 0xf3, + 0xf5, 0xb7, 0xd9, 0x9a, 0x8a, 0x72, 0xa0, 0xc0, 0xcd, 0x67, 0xa0, 0x8a, 0xc6, 0xcc, 0xa0, 0x51, + 0xf9, 0x4d, 0x0c, 0x96, 0x54, 0xdb, 0xc7, 0xae, 0x85, 0xf5, 0x23, 0x1c, 0x09, 0xc4, 0x17, 0x20, + 0xea, 0xf6, 0x00, 0x7b, 0xbe, 0xe3, 0x7a, 0x25, 0x81, 0x1e, 0x3d, 0x9f, 0x5c, 0x92, 0x31, 0x17, + 0xd9, 0x57, 0x6b, 0xcc, 0x98, 0x9f, 0xe5, 0x21, 0x58, 0xf9, 0x77, 0x02, 0x64, 0xf8, 0x28, 0xba, + 0x0f, 0x19, 0x4a, 0x59, 0xc4, 0x8f, 0x80, 0xce, 0x6e, 0x32, 0x3f, 0xd2, 0x5d, 0x22, 0xa7, 0xeb, + 0x27, 0x3b, 0x9f, 0xa6, 0x6a, 0xaa, 0x81, 0xfe, 0x1b, 0x32, 0x94, 0xbd, 0x7a, 0xe1, 0x6e, 0x94, + 0xb9, 0x05, 0xa3, 0xb7, 0x28, 0xd3, 0xa5, 0xa9, 0xae, 0x6a, 0xa0, 0xc6, 0x45, 0x24, 0x14, 0xa7, + 0xf6, 0x6f, 0xf0, 0xc8, 0x75, 0x66, 0x69, 0xe8, 0x1c, 0x2f, 0x55, 0xfe, 0x1e, 0x87, 0x5b, 0x3b, + 0xba, 0xeb, 0x9b, 0xa4, 0xde, 0x4d, 0xfb, 0x20, 0x12, 0xaf, 0x7b, 0x90, 0xb5, 0xc7, 0x43, 0xb6, + 0x2b, 0x1e, 0xf3, 0x25, 0xf0, 0x1d, 0xec, 0xf1, 0x30, 0x08, 0xb8, 0x87, 0x9a, 0x90, 0xb0, 0x4c, + 0xcf, 0x2f, 0xc5, 0x68, 0x44, 0x37, 0x2e, 0x89, 0xe8, 0xc5, 0x73, 0x54, 0x9b, 0xa6, 0xe7, 0xf3, + 0x9c, 0x24, 0x28, 0xa8, 0x0d, 0x49, 0x57, 0xb7, 0x0f, 0x30, 0x4d, 0xb2, 0xec, 0xc6, 0x83, 0xeb, + 0xc1, 0x69, 0xc4, 0x94, 0xf7, 0x62, 0x14, 0xa7, 0xfc, 0x2b, 0x01, 0x12, 0x64, 0x96, 0x2b, 0xea, + 0xe0, 0x16, 0xa4, 0x8e, 0x74, 0x6b, 0x8c, 0x3d, 0xea, 0x43, 0x4e, 0x63, 0x5f, 0xe8, 0xe7, 0x50, + 0xf4, 0xc6, 0xfd, 0x51, 0x64, 0x2a, 0x46, 0x34, 0x1f, 0x5d, 0x6b, 0x55, 0xe1, 0x91, 0x30, 0x8b, + 0x55, 0x7e, 0x0e, 0x49, 0xba, 0xde, 0x2b, 0x56, 0x46, 0x5a, 0x1c, 0xa7, 0x87, 0x8f, 0x07, 0xd6, + 0xd8, 0x33, 0x8f, 0x30, 0xcd, 0x8e, 0x9c, 0x96, 0xf5, 0x1d, 0x85, 0x8b, 0xd0, 0x3d, 0x28, 0xec, + 0xbb, 0xce, 0xb0, 0x67, 0xda, 0x5c, 0x29, 0x4e, 0x95, 0xf2, 0x44, 0xaa, 0x72, 0x61, 0xe5, 0xdf, + 0x19, 0x28, 0xd2, 0x0c, 0x9a, 0x8b, 0x19, 0xee, 0x45, 0x98, 0xe1, 0xe6, 0x0c, 0x33, 0x84, 0x69, + 0x48, 0x88, 0xe1, 0x0e, 0xa4, 0xc6, 0xb6, 0xf9, 0x62, 0x1c, 0xcc, 0x19, 0x92, 0x5f, 0x20, 0x3b, + 0x47, 0x1b, 0x89, 0xf3, 0xb4, 0xf1, 0x21, 0x20, 0x52, 0x33, 0xb8, 0x37, 0xa3, 0x98, 0xa4, 0x8a, + 0x12, 0x1d, 0x69, 0x5c, 0x4a, 0x32, 0xa9, 0x6b, 0x90, 0xcc, 0x23, 0x90, 0xf0, 0xb1, 0xef, 0xea, + 0xbd, 0x88, 0x7d, 0x9a, 0xda, 0x2f, 0x9f, 0x9e, 0xac, 0x14, 0x14, 0x32, 0x76, 0x31, 0x48, 0x01, + 0x47, 0xc6, 0x0c, 0x92, 0x13, 0x8b, 0x0c, 0xc3, 0x30, 0x5d, 0x4c, 0x4f, 0xc9, 0xa0, 0x8f, 0x2d, + 0x6c, 0xdc, 0xbf, 0x94, 0x4c, 0x66, 0xc2, 0x5e, 0x95, 0xb9, 0xa1, 0x26, 0x05, 0x50, 0xa1, 0xc0, + 0x43, 0x4f, 0x20, 0xbb, 0x1f, 0x1c, 0xd4, 0xbd, 0xe7, 0x78, 0x52, 0x12, 0x69, 0xba, 0xbd, 0x3f, + 0xff, 0x91, 0xce, 0xeb, 0x73, 0x3f, 0x1c, 0x42, 0xbb, 0x90, 0x77, 0xf9, 0xb0, 0xd1, 0xeb, 0x4f, + 0xe8, 0xf9, 0xf3, 0x2a, 0xa0, 0xb9, 0x29, 0x4c, 0x7d, 0x82, 0x9e, 0x00, 0x98, 0x21, 0x4b, 0xd2, + 0x43, 0x2a, 0xbb, 0xf1, 0xc1, 0x35, 0xe8, 0x94, 0xaf, 0x74, 0x0a, 0x82, 0x9e, 0x42, 0x61, 0xfa, + 0x45, 0x97, 0x9a, 0x7b, 0xc5, 0xa5, 0xe6, 0x23, 0x38, 0xf5, 0x09, 0xea, 0xc2, 0x12, 0x39, 0x3e, + 0x1d, 0xcf, 0xf4, 0x71, 0x34, 0x05, 0xf2, 0x34, 0x05, 0x2a, 0xa7, 0x27, 0x2b, 0xa8, 0xc1, 0xc7, + 0x2f, 0x4e, 0x03, 0x34, 0x38, 0x33, 0x1e, 0x24, 0xd5, 0x4c, 0xf2, 0x12, 0xc4, 0xc2, 0x34, 0xa9, + 0x3a, 0xd3, 0xf4, 0x3d, 0x97, 0x54, 0x91, 0xd4, 0x26, 0x48, 0x4f, 0x21, 0x37, 0xc3, 0x32, 0xc5, + 0x57, 0x67, 0x99, 0x19, 0x20, 0xa4, 0xb0, 0xfe, 0x48, 0xa2, 0xad, 0xe1, 0x07, 0x73, 0x26, 0xe8, + 0xd9, 0x4e, 0xa9, 0xb2, 0x0c, 0x62, 0x98, 0xa3, 0xa4, 0xe5, 0xaf, 0x75, 0x1a, 0xd2, 0x02, 0xbd, + 0x20, 0x29, 0x9d, 0x86, 0x24, 0x54, 0xee, 0x42, 0x82, 0x5e, 0x1f, 0xb2, 0x90, 0xde, 0x6c, 0x6b, + 0x4f, 0x6b, 0x9a, 0x1c, 0x34, 0x8b, 0x6a, 0x6b, 0x4f, 0xd1, 0xba, 0x8a, 0x2c, 0x09, 0x95, 0x1f, + 0x12, 0x80, 0xa6, 0x53, 0x6c, 0x8f, 0x7d, 0x9d, 0x82, 0xd5, 0x20, 0x15, 0x44, 0x8f, 0x92, 0x50, + 0x76, 0xe3, 0xbf, 0xae, 0x6c, 0xe1, 0xa6, 0x00, 0x8f, 0x16, 0x34, 0x66, 0x88, 0x3e, 0x8f, 0xde, + 0x0c, 0xb2, 0x1b, 0xef, 0xce, 0xe7, 0xe4, 0xa3, 0x05, 0x7e, 0x65, 0x78, 0x0c, 0x49, 0xcf, 0x27, + 0xfd, 0x73, 0x9c, 0x06, 0x69, 0xfd, 0x12, 0xfb, 0xf3, 0x8b, 0xaf, 0x76, 0x88, 0x19, 0x3f, 0x6d, + 0x28, 0x06, 0x7a, 0x0a, 0x62, 0xc8, 0x0b, 0xec, 0x9a, 0xf1, 0x60, 0x7e, 0xc0, 0x30, 0xc8, 0xbc, + 0xc5, 0x08, 0xb1, 0x50, 0x0d, 0xb2, 0x43, 0xa6, 0x36, 0x6d, 0x90, 0x56, 0x19, 0x35, 0x03, 0x47, + 0xa0, 0x14, 0x1d, 0xf9, 0xd2, 0x80, 0x1b, 0xa9, 0x06, 0xe9, 0x77, 0x5d, 0xc7, 0xb2, 0xfa, 0xfa, + 0xe0, 0x39, 0xbd, 0x2b, 0x84, 0xfd, 0x2e, 0x97, 0x56, 0x7e, 0x06, 0x49, 0xea, 0x13, 0xd9, 0xc8, + 0xdd, 0xd6, 0xe3, 0x56, 0xfb, 0x29, 0xe9, 0xfa, 0x8b, 0x90, 0x95, 0x95, 0xa6, 0xd2, 0x55, 0x7a, + 0xed, 0x56, 0xf3, 0x99, 0x24, 0xa0, 0xdb, 0x70, 0x93, 0x09, 0x6a, 0x2d, 0xb9, 0xf7, 0x54, 0x53, + 0xf9, 0x50, 0xac, 0xb2, 0x16, 0xcd, 0x94, 0xe9, 0x6d, 0x92, 0xe4, 0x8c, 0x2c, 0x4b, 0x02, 0xcd, + 0x19, 0xad, 0xbd, 0x23, 0xc5, 0xea, 0x39, 0x00, 0x23, 0x8c, 0xc0, 0x56, 0x22, 0x93, 0x92, 0xd2, + 0x95, 0x7f, 0x96, 0xa0, 0x48, 0x7b, 0xa4, 0xb9, 0x0e, 0xa9, 0x55, 0x7a, 0x48, 0x05, 0x0d, 0x8f, + 0x34, 0x73, 0x48, 0xc5, 0xd8, 0xf9, 0xf4, 0x00, 0xc4, 0x91, 0xee, 0x62, 0xdb, 0x27, 0x21, 0x4b, + 0xcc, 0xf4, 0xb9, 0x99, 0x1d, 0x3a, 0x10, 0xaa, 0x67, 0x02, 0x45, 0x95, 0x18, 0xa5, 0x8f, 0xb0, + 0x4b, 0x9f, 0x6e, 0x82, 0x28, 0xdf, 0x66, 0x77, 0xcd, 0xc5, 0xe9, 0xaa, 0xf6, 0x02, 0x05, 0x8d, + 0x6b, 0xa2, 0xb7, 0x01, 0xc6, 0xa3, 0x1e, 0xb7, 0x8b, 0x5e, 0x05, 0xc4, 0xf1, 0x88, 0x69, 0xa3, + 0x1d, 0x58, 0x1c, 0x3a, 0x86, 0xb9, 0x6f, 0x0e, 0x82, 0x7d, 0xf4, 0xcd, 0x61, 0x70, 0x6b, 0xcb, + 0x6e, 0xbc, 0x15, 0x49, 0x92, 0xb1, 0x6f, 0x5a, 0xd5, 0x43, 0x6b, 0x50, 0xed, 0xf2, 0xf7, 0x30, + 0x06, 0x25, 0x45, 0xad, 0xc9, 0x20, 0x7a, 0x08, 0x69, 0xde, 0x9e, 0x05, 0x6f, 0x29, 0xf3, 0xd6, + 0x0f, 0x43, 0xe4, 0xd6, 0x68, 0x13, 0x0a, 0x36, 0x3e, 0x8e, 0xb6, 0xe0, 0xe2, 0x4c, 0x86, 0xe5, + 0x5a, 0xf8, 0xf8, 0xe2, 0xfe, 0x3b, 0x67, 0x4f, 0x47, 0x0c, 0xf4, 0x04, 0xf2, 0x23, 0xd7, 0x1c, + 0xea, 0xee, 0xa4, 0x17, 0x14, 0x25, 0x5c, 0xa7, 0x28, 0x43, 0x0e, 0x0b, 0x20, 0xe8, 0x28, 0xda, + 0x84, 0xa0, 0xe3, 0xc5, 0x5e, 0x29, 0x4b, 0x7d, 0xbc, 0x1e, 0x18, 0x37, 0x46, 0x75, 0xc8, 0x53, + 0x17, 0xc3, 0x56, 0x3b, 0x47, 0x3d, 0x5c, 0x66, 0x1e, 0x66, 0x89, 0x87, 0x17, 0xb4, 0xdb, 0x59, + 0x3b, 0x94, 0x1b, 0x68, 0x0b, 0x20, 0x7c, 0x87, 0x24, 0xc7, 0xc7, 0x55, 0xa7, 0xf3, 0x0e, 0x57, + 0x9c, 0x2e, 0x49, 0x8b, 0x58, 0xa3, 0x6d, 0x10, 0x79, 0x71, 0x06, 0xe7, 0x46, 0xf6, 0xd2, 0x17, + 0x89, 0xf3, 0x54, 0xc1, 0x93, 0x2b, 0x44, 0x40, 0x2d, 0x48, 0x5a, 0x58, 0xf7, 0x30, 0x3b, 0x3c, + 0x3e, 0xbd, 0x04, 0xea, 0x4c, 0x79, 0x55, 0x3b, 0x83, 0x43, 0x3c, 0xd4, 0x1b, 0x87, 0xa4, 0x11, + 0x6d, 0x12, 0x7b, 0x2d, 0x80, 0x41, 0x2d, 0x90, 0x68, 0xb8, 0xa2, 0xac, 0x23, 0xd1, 0x88, 0xbd, + 0xc3, 0x22, 0x56, 0x20, 0x11, 0xbb, 0x94, 0x79, 0x68, 0x3e, 0x6d, 0x4f, 0xd9, 0xe7, 0xff, 0xa1, + 0xb0, 0xef, 0xb8, 0x43, 0xdd, 0x0f, 0xab, 0x64, 0x71, 0xda, 0x5e, 0xfe, 0x78, 0xb2, 0x92, 0xdf, + 0xa4, 0xa3, 0xbc, 0xb2, 0xf2, 0xfb, 0xd1, 0x4f, 0xf4, 0x88, 0x93, 0xf4, 0x0d, 0xca, 0xa9, 0x1f, + 0xce, 0xeb, 0xdd, 0x79, 0x86, 0x6e, 0x41, 0x6a, 0x70, 0x88, 0x07, 0xcf, 0xbd, 0xd2, 0x12, 0x8d, + 0xf9, 0xff, 0xcc, 0x09, 0xd5, 0x20, 0x46, 0xd3, 0xa7, 0x21, 0x8d, 0xa1, 0xa0, 0xaf, 0xa0, 0x60, + 0x10, 0x89, 0x69, 0x1f, 0xb0, 0xf6, 0xf5, 0x26, 0xc5, 0x5d, 0x9f, 0x13, 0x97, 0xb4, 0xb6, 0xaa, + 0xbd, 0xef, 0xf0, 0xce, 0x85, 0x83, 0x05, 0x2d, 0x6f, 0x1b, 0x32, 0xfb, 0xe4, 0x2a, 0x6e, 0x62, + 0xaf, 0x74, 0x8b, 0xe2, 0x5e, 0xfd, 0xbc, 0x7b, 0xf6, 0xf6, 0xcf, 0x29, 0x9e, 0x83, 0x84, 0x85, + 0x4e, 0x05, 0x13, 0xb2, 0xa9, 0x6f, 0x9c, 0x2f, 0x74, 0x7e, 0xfb, 0x9f, 0x79, 0x09, 0xa0, 0x85, + 0xce, 0xbe, 0x0c, 0x42, 0x78, 0x47, 0x26, 0xfe, 0xa6, 0xf7, 0x62, 0x8c, 0xdd, 0x49, 0xa9, 0x14, + 0x21, 0x67, 0x91, 0xc8, 0x9f, 0x10, 0x31, 0xfa, 0x18, 0x44, 0x03, 0x8f, 0xb0, 0x6d, 0x78, 0x6d, + 0xbb, 0x74, 0x9b, 0xb6, 0x46, 0x37, 0x48, 0xbf, 0x2e, 0x73, 0x21, 0x23, 0xdf, 0xa9, 0x16, 0xfa, + 0x1a, 0x72, 0xc1, 0x07, 0x36, 0xda, 0x76, 0x7d, 0x52, 0x2a, 0x53, 0xa7, 0xef, 0xcf, 0x19, 0xcc, + 0x69, 0x1f, 0xb8, 0xc4, 0xfd, 0x91, 0x23, 0x68, 0xda, 0x0c, 0x36, 0xfa, 0x0a, 0x72, 0x3c, 0xbb, + 0xb7, 0x9c, 0xbe, 0x57, 0x7a, 0xf3, 0xca, 0x1b, 0xec, 0xd9, 0xb9, 0xb6, 0xa7, 0xa6, 0x9c, 0xb7, + 0xa2, 0x68, 0xe8, 0x0b, 0xc8, 0x87, 0xcf, 0x3e, 0xce, 0xc8, 0xf7, 0x4a, 0x77, 0x68, 0x61, 0x3e, + 0x98, 0x37, 0x75, 0x99, 0x6d, 0x7b, 0xe4, 0x7b, 0x5a, 0xce, 0x8b, 0x7c, 0xa1, 0xbb, 0x20, 0x1a, + 0xae, 0x33, 0x0a, 0xce, 0x8f, 0xb7, 0x56, 0x85, 0xb5, 0x38, 0xdf, 0x66, 0x22, 0xa6, 0x07, 0x43, + 0x0f, 0x0a, 0x2e, 0x1e, 0x59, 0xfa, 0x00, 0x0f, 0xc9, 0xf1, 0xe7, 0xec, 0x97, 0x96, 0xe9, 0xec, + 0x1b, 0x73, 0x07, 0x32, 0x34, 0xe6, 0x89, 0x19, 0xc1, 0x6b, 0xef, 0xa3, 0x5d, 0x00, 0x7d, 0x6c, + 0x98, 0x7e, 0x6f, 0xe8, 0x18, 0xb8, 0xb4, 0x42, 0xab, 0x72, 0xde, 0x5d, 0xaa, 0x11, 0xc3, 0x6d, + 0xc7, 0xc0, 0xe1, 0x4b, 0x0a, 0x17, 0x94, 0x7f, 0x10, 0x60, 0xf1, 0x1c, 0x25, 0xa1, 0x5f, 0x40, + 0xda, 0x76, 0x8c, 0xc8, 0x8b, 0x8a, 0xc2, 0x76, 0x37, 0xd5, 0x72, 0x8c, 0xe0, 0x41, 0xe5, 0xc1, + 0x81, 0xe9, 0x1f, 0x8e, 0xfb, 0xd5, 0x81, 0x33, 0x5c, 0x0f, 0x57, 0x61, 0xf4, 0xa7, 0xbf, 0xd7, + 0x47, 0xcf, 0x0f, 0xd6, 0xe9, 0xaf, 0x51, 0xbf, 0x1a, 0x98, 0x69, 0x29, 0x82, 0xaa, 0x1a, 0xe8, + 0x23, 0x28, 0xe2, 0xe3, 0x91, 0xe9, 0x46, 0x8e, 0xe5, 0x58, 0x24, 0xac, 0x85, 0xe9, 0x20, 0x09, + 0x6e, 0xf9, 0x8f, 0x02, 0x14, 0xcf, 0xd0, 0x01, 0x69, 0x53, 0xe8, 0x6b, 0xdd, 0x4c, 0x9b, 0x42, + 0x24, 0x61, 0x03, 0x13, 0xbb, 0xf2, 0x49, 0x3a, 0xfe, 0xba, 0x4f, 0xd2, 0xb3, 0x97, 0xe3, 0xe4, + 0xfc, 0x97, 0xe3, 0xad, 0x44, 0x26, 0x21, 0x25, 0xcb, 0xcf, 0x20, 0xc3, 0xa9, 0x68, 0xb6, 0x6f, + 0x12, 0xe6, 0xec, 0x9b, 0x2e, 0xf5, 0xb3, 0xfc, 0x9d, 0x00, 0x62, 0xf4, 0xad, 0x3f, 0x16, 0xa2, + 0x5e, 0xdc, 0xb6, 0xbd, 0xe2, 0x7b, 0xd8, 0x6c, 0x04, 0xe2, 0xf3, 0x47, 0xa0, 0x7c, 0x04, 0xd9, + 0x48, 0x35, 0x9f, 0xed, 0xb5, 0x85, 0x57, 0xe8, 0xb5, 0xdf, 0x81, 0xd4, 0xd7, 0x4e, 0x9f, 0x3b, + 0x10, 0xaf, 0xe7, 0x99, 0x75, 0x72, 0xcb, 0xe9, 0xab, 0xb2, 0x96, 0xfc, 0xda, 0xe9, 0xab, 0x46, + 0xf9, 0xb7, 0x02, 0xe4, 0xa2, 0x75, 0x8e, 0x2a, 0x20, 0x9a, 0xf6, 0xc0, 0xa5, 0x45, 0x46, 0xe7, + 0xe5, 0x29, 0x38, 0x15, 0x93, 0xea, 0x1f, 0x9a, 0x76, 0x8f, 0xbe, 0x51, 0xcd, 0xa4, 0x69, 0x66, + 0x68, 0xda, 0x7b, 0x44, 0x4a, 0x55, 0xf4, 0x63, 0xa6, 0x12, 0x9f, 0x51, 0xd1, 0x8f, 0x03, 0x95, + 0x32, 0x3d, 0x50, 0x5d, 0x9f, 0xb6, 0xc5, 0xf1, 0xc8, 0x11, 0xe9, 0xfa, 0x68, 0x19, 0xd2, 0x47, + 0xa6, 0xeb, 0x8f, 0x75, 0x8b, 0x76, 0xc0, 0xbc, 0x93, 0xe5, 0xc2, 0xf2, 0x21, 0x64, 0x23, 0xfc, + 0x30, 0xc7, 0x86, 0xfe, 0x2f, 0x24, 0xc2, 0xa2, 0x9a, 0xb3, 0xd7, 0xa5, 0x06, 0x95, 0x77, 0xf9, + 0x85, 0x04, 0x20, 0xb5, 0xb3, 0x5b, 0x6f, 0xaa, 0x8d, 0x0b, 0x2f, 0x13, 0xe4, 0xda, 0x11, 0x92, + 0x0a, 0xb9, 0x78, 0xca, 0x6a, 0xa7, 0x56, 0x6f, 0x2a, 0xe4, 0x1a, 0x9a, 0x07, 0x51, 0x53, 0x6a, + 0x32, 0xbd, 0xa5, 0x48, 0xc2, 0x67, 0x89, 0x6f, 0xbf, 0x5f, 0x11, 0xb6, 0x12, 0x19, 0x24, 0xdd, + 0xa8, 0xfc, 0x20, 0x00, 0x92, 0x75, 0x5f, 0x27, 0x25, 0x76, 0x8d, 0x1b, 0x47, 0xec, 0x0a, 0x4f, + 0x67, 0x1b, 0xc4, 0xf8, 0xeb, 0x34, 0x88, 0xc1, 0x52, 0x2b, 0xdf, 0x09, 0x00, 0x91, 0xc5, 0x7d, + 0x1e, 0xfd, 0xa7, 0xec, 0xf2, 0x5e, 0xf8, 0x0c, 0xe5, 0x92, 0xdb, 0x6e, 0xf0, 0x3f, 0xda, 0x43, + 0xc8, 0x18, 0xcc, 0x65, 0xb6, 0x1d, 0x97, 0x36, 0x9d, 0xe7, 0x22, 0xf3, 0x88, 0x9c, 0x30, 0x4c, + 0x5a, 0x4f, 0x43, 0x72, 0x6c, 0x9b, 0x8e, 0xfd, 0xfe, 0x27, 0x80, 0xce, 0xd3, 0x13, 0x09, 0x3b, + 0xfd, 0xad, 0xfb, 0xd8, 0x08, 0xee, 0x90, 0xbb, 0xf6, 0x51, 0x28, 0x10, 0xea, 0x77, 0x5f, 0xfe, + 0x75, 0x79, 0xe1, 0xe5, 0xe9, 0xb2, 0xf0, 0x87, 0xd3, 0x65, 0xe1, 0x4f, 0xa7, 0xcb, 0xc2, 0x5f, + 0x4e, 0x97, 0x85, 0x5f, 0xfe, 0x6d, 0x79, 0xe1, 0xcb, 0x34, 0x5b, 0xc0, 0x7f, 0x02, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0x0c, 0xa9, 0x24, 0x4e, 0x20, 0x00, 0x00, } diff --git a/pkg/sql/sqlbase/structured.proto b/pkg/sql/sqlbase/structured.proto index d37d563f0fe4..7807dd03706b 100644 --- a/pkg/sql/sqlbase/structured.proto +++ b/pkg/sql/sqlbase/structured.proto @@ -696,6 +696,8 @@ message TableDescriptor { optional int64 max_value = 3 [(gogoproto.nullable) = false]; // Start value of the sequence. optional int64 start = 4 [(gogoproto.nullable) = false]; + // Whether the sequence is virtual. + optional bool virtual = 5 [(gogoproto.nullable) = false]; } // The presence of sequence_opts indicates that this descriptor is for a sequence. From fc173bbf2e994dd1a992c6b356e88b683c1e98a9 Mon Sep 17 00:00:00 2001 From: Raphael 'kena' Poss Date: Wed, 15 Aug 2018 14:06:57 +0200 Subject: [PATCH 2/3] sql: hoist seq creation from `(*createSequenceNode).startExec()` This will enable reuse in other places. Release note: None --- pkg/sql/create_sequence.go | 45 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/pkg/sql/create_sequence.go b/pkg/sql/create_sequence.go index 28215f2d03ab..3c7b36f3eb60 100644 --- a/pkg/sql/create_sequence.go +++ b/pkg/sql/create_sequence.go @@ -56,10 +56,8 @@ func (p *planner) CreateSequence(ctx context.Context, n *tree.CreateSequence) (p } func (n *createSequenceNode) startExec(params runParams) error { - seqName := n.n.Name.TableName().Table() - tKey := tableKey{parentID: n.dbDesc.ID, name: seqName} - key := tKey.Key() - if exists, err := descExists(params.ctx, params.p.txn, key); err == nil && exists { + tKey := getSequenceKey(n.dbDesc, n.n.Name.TableName().Table()) + if exists, err := descExists(params.ctx, params.p.txn, tKey.Key()); err == nil && exists { if n.n.IfNotExists { // If the sequence exists but the user specified IF NOT EXISTS, return without doing anything. return nil @@ -69,23 +67,40 @@ func (n *createSequenceNode) startExec(params runParams) error { return err } + return doCreateSequence(params, n.n.String(), n.dbDesc, n.n.Name.TableName(), n.n.Options) +} + +func getSequenceKey(dbDesc *DatabaseDescriptor, seqName string) tableKey { + return tableKey{parentID: dbDesc.ID, name: seqName} +} + +// doCreateSequence performs the creation of a sequence in KV. The +// context argument is a string to use in the event log. +func doCreateSequence( + params runParams, + context string, + dbDesc *DatabaseDescriptor, + name *ObjectName, + opts tree.SequenceOptions, +) error { id, err := GenerateUniqueDescID(params.ctx, params.p.ExecCfg().DB) if err != nil { return err } // Inherit permissions from the database descriptor. - privs := n.dbDesc.GetPrivileges() + privs := dbDesc.GetPrivileges() - desc, err := n.makeSequenceTableDesc(params, seqName, n.dbDesc.ID, id, privs) + desc, err := MakeSequenceTableDesc(name.Table(), opts, + dbDesc.ID, id, params.p.txn.CommitTimestamp(), privs, params.EvalContext().Settings) if err != nil { return err } - if err = desc.ValidateTable(params.EvalContext().Settings); err != nil { - return err - } + // makeSequenceTableDesc already validates the table. No call to + // desc.ValidateTable() needed here. + key := getSequenceKey(dbDesc, name.Table()).Key() if err = params.p.createDescriptorWithID(params.ctx, key, id, &desc); err != nil { return err } @@ -117,7 +132,7 @@ func (n *createSequenceNode) startExec(params runParams) error { SequenceName string Statement string User string - }{n.n.Name.TableName().FQString(), n.n.String(), params.SessionData().User}, + }{name.FQString(), context, params.SessionData().User}, ) } @@ -130,16 +145,6 @@ const ( sequenceColumnName = "value" ) -func (n *createSequenceNode) makeSequenceTableDesc( - params runParams, - sequenceName string, - parentID sqlbase.ID, - id sqlbase.ID, - privileges *sqlbase.PrivilegeDescriptor, -) (sqlbase.TableDescriptor, error) { - return MakeSequenceTableDesc(sequenceName, n.n.Options, parentID, id, params.p.txn.CommitTimestamp(), privileges, params.EvalContext().Settings) -} - // MakeSequenceTableDesc creates a sequence descriptor. func MakeSequenceTableDesc( sequenceName string, From 46e0449644927c079b8dd5a2d6fb94ff84eb7e6c Mon Sep 17 00:00:00 2001 From: Raphael 'kena' Poss Date: Wed, 15 Aug 2018 16:31:08 +0200 Subject: [PATCH 3/3] sql: make the SERIAL pseudo-type optionally auto-create sequence Prior to this patch, SERIAL in CockroachDB was always alias for `INT DEFAULT unique_rowid()`. However 3rd party apps developed for PostgreSQL expect SERIAL to associate a column with a SQL sequence. Although the particular values produced for the SERIAL column rarely matter to the client app, we have found in practice that client apps (or ORM frameworks) are likely to assert that there is a sequence object created in the namespace with a particular name, and that they are able to call `nextval()` / `currval()` on that object while populating new rows on the table. This patch increases compatibility with those apps by optionally associating SERIAL columns to sequences like PostgreSQL. This behavior is driven by a new session variable called `experimental_serial_normalization`. Its default for new SQL sessions is configured via the new cluster setting `sql.defaults.serial_normalization`. The three values are: - `rowid` (the default): SERIAL behaves like before and expands to `INT NOT NULL DEFAULT unique_rowid()`. The SERIAL width (SMALLSERIAL/SERIAL4/etc) is ignored. - `virtual_sequence`: SERIAL creates a virtual sequence and expands to `INT NOT NULL DEFAULT nextval(...seqname...)`. The SERIAL width (SMALLSERIAL/SERIAL4/etc) is ignored. - `sql_sequence`: This is the PostgreSQL "stricter" compatibility mode. SERIAL creates a regular SQL sequence and expands to `...inttype... NOT NULL DEFAULT nextval(...seqname...)`. The SERIAL width (SMALLSERIAL/SERIAL4/etc) is respected. Finally, this patch ensures that SERIAL always implies NOT NULL, as required for PostgreSQL compatibility, even when SERIAL is not used as PRIMARY KEY. Release note (sql change): CockroachDB now supports two experimental compatibility modes with how PostgreSQL handles SERIAL and sequences, to ease reuse of 3rd party frameworks or apps developed for PostgreSQL. These modes can be enabled with the session variable `experimental_serial_normalization` (per client) and cluster setting `sql.defaults.serial_normalization` (cluster-wide). The first mode `virtual_sequence` enables compatibility with many applications using SERIAL with maximum performance and scalability. The second mode `sql_sequence` enables maximum PostgreSQL compatibility but thus uses regular SQL sequences and is thus subject to performance constraints. --- pkg/ccl/importccl/import_stmt.go | 27 +- pkg/ccl/importccl/import_stmt_test.go | 52 ++-- pkg/ccl/importccl/load.go | 2 + pkg/ccl/importccl/read_import_mysql.go | 6 + pkg/sql/alter_table.go | 12 + pkg/sql/coltypes/aliases.go | 4 - pkg/sql/coltypes/arith.go | 10 +- pkg/sql/conn_executor.go | 17 +- pkg/sql/create_table.go | 61 ++++- pkg/sql/create_view.go | 2 + pkg/sql/exec_util.go | 17 ++ .../logictest/testdata/logic_test/pg_catalog | 191 +++++++------- pkg/sql/logictest/testdata/logic_test/serial | 235 +++++++++++++++++- .../logictest/testdata/logic_test/show_source | 63 ++--- pkg/sql/logictest/testdata/logic_test/table | 13 +- .../logictest/testdata/planner_test/explain | 10 +- pkg/sql/opt/exec/execbuilder/testdata/explain | 10 +- pkg/sql/parser/parse_test.go | 5 +- pkg/sql/parser/sql.y | 4 +- pkg/sql/sem/tree/create.go | 3 + pkg/sql/serial.go | 215 ++++++++++++++++ pkg/sql/sessiondata/session_data.go | 43 ++++ pkg/sql/sqlbase/structured_test.go | 8 +- pkg/sql/sqlbase/table.go | 22 +- pkg/sql/vars.go | 29 +++ pkg/sql/virtual_schema.go | 2 + 26 files changed, 856 insertions(+), 207 deletions(-) create mode 100644 pkg/sql/serial.go diff --git a/pkg/ccl/importccl/import_stmt.go b/pkg/ccl/importccl/import_stmt.go index bc375cae3bc2..a5506a6dbaa1 100644 --- a/pkg/ccl/importccl/import_stmt.go +++ b/pkg/ccl/importccl/import_stmt.go @@ -136,6 +136,10 @@ var NoFKs = fkHandler{} // node without the full machinery. Many parts of the syntax are unsupported // (see the implementation and TestMakeSimpleTableDescriptorErrors for details), // but this is enough for our csv IMPORT and for some unit tests. +// +// Any occurrence of SERIAL in the column definitions is handled using +// the CockroachDB legacy behavior, i.e. INT NOT NULL DEFAULT +// unique_rowid(). func MakeSimpleTableDescriptor( ctx context.Context, st *cluster.Settings, @@ -145,7 +149,6 @@ func MakeSimpleTableDescriptor( fks fkHandler, walltime int64, ) (*sqlbase.TableDescriptor, error) { - sql.HoistConstraints(create) if create.IfNotExists { return nil, errors.New("unsupported IF NOT EXISTS") @@ -156,6 +159,12 @@ func MakeSimpleTableDescriptor( if create.AsSource != nil { return nil, errors.New("CREATE AS not supported") } + + tableName, err := create.Table.Normalize() + if err != nil { + return nil, err + } + filteredDefs := create.Defs[:0] for i := range create.Defs { switch def := create.Defs[i].(type) { @@ -168,6 +177,11 @@ func MakeSimpleTableDescriptor( if def.Computed.Expr != nil { return nil, errors.Errorf("computed columns not supported: %s", tree.AsString(def)) } + + if err := sql.SimplifySerialInColumnDefWithRowID(ctx, def, tableName); err != nil { + return nil, err + } + case *tree.ForeignKeyConstraintTableDef: if !fks.allowed { return nil, errors.Errorf("this IMPORT format does not support foreign keys") @@ -175,8 +189,14 @@ func MakeSimpleTableDescriptor( if fks.skip { continue } - n := tree.MakeTableName("", tree.Name(def.Table.TableNameReference.String())) - def.Table.TableNameReference = &n + // Strip the schema/db prefix. + refTable, err := def.Table.Normalize() + if err != nil { + return nil, err + } + *refTable = tree.MakeUnqualifiedTableName(refTable.TableName) + def.Table.TableNameReference = refTable + default: return nil, errors.Errorf("unsupported table definition: %s", tree.AsString(def)) } @@ -191,6 +211,7 @@ func MakeSimpleTableDescriptor( Sequence: &importSequenceOperators{}, } affected := make(map[sqlbase.ID]*sqlbase.TableDescriptor) + tableDesc, err := sql.MakeTableDesc( ctx, nil, /* txn */ diff --git a/pkg/ccl/importccl/import_stmt_test.go b/pkg/ccl/importccl/import_stmt_test.go index 8cec0cbdf8db..362bee3b5b0d 100644 --- a/pkg/ccl/importccl/import_stmt_test.go +++ b/pkg/ccl/importccl/import_stmt_test.go @@ -1274,29 +1274,43 @@ func TestImportCSVStmt(t *testing.T) { nullif = ` WITH nullif=''` ) - data = ",5,e,,," - if _, err := conn.Exec(query, srv.URL); !testutils.IsError(err, `row 1: parse "a" as INT: could not parse ""`) { - t.Fatalf("unexpected: %v", err) - } - if _, err := conn.Exec(query+nullif, srv.URL); !testutils.IsError(err, `row 1: generate insert row: null value in column "a" violates not-null constraint`) { - t.Fatalf("unexpected: %v", err) - } + data = ",5,e,7,," + t.Run(data, func(t *testing.T) { + if _, err := conn.Exec(query, srv.URL); !testutils.IsError(err, `row 1: parse "a" as INT: could not parse ""`) { + t.Fatalf("unexpected: %v", err) + } + if _, err := conn.Exec(query+nullif, srv.URL); !testutils.IsError(err, `row 1: generate insert row: null value in column "a" violates not-null constraint`) { + t.Fatalf("unexpected: %v", err) + } + }) + data = "2,5,e,,," + t.Run(data, func(t *testing.T) { + if _, err := conn.Exec(query+nullif, srv.URL); !testutils.IsError(err, `row 1: generate insert row: null value in column "d" violates not-null constraint`) { + t.Fatalf("unexpected: %v", err) + } + }) data = "2,,e,,," - if _, err := conn.Exec(query+nullif, srv.URL); !testutils.IsError(err, `"b" violates not-null constraint`) { - t.Fatalf("unexpected: %v", err) - } + t.Run(data, func(t *testing.T) { + if _, err := conn.Exec(query+nullif, srv.URL); !testutils.IsError(err, `"b" violates not-null constraint`) { + t.Fatalf("unexpected: %v", err) + } + }) data = "2,5,,,," - if _, err := conn.Exec(query+nullif, srv.URL); !testutils.IsError(err, `"c" violates not-null constraint`) { - t.Fatalf("unexpected: %v", err) - } + t.Run(data, func(t *testing.T) { + if _, err := conn.Exec(query+nullif, srv.URL); !testutils.IsError(err, `"c" violates not-null constraint`) { + t.Fatalf("unexpected: %v", err) + } + }) - data = "2,5,e,,," - sqlDB.Exec(t, query+nullif, srv.URL) - sqlDB.CheckQueryResults(t, - `SELECT * FROM t`, - sqlDB.QueryStr(t, `SELECT 2, 5, 'e', NULL, NULL, NULL`), - ) + data = "2,5,e,-1,," + t.Run(data, func(t *testing.T) { + sqlDB.Exec(t, query+nullif, srv.URL) + sqlDB.CheckQueryResults(t, + `SELECT * FROM t`, + sqlDB.QueryStr(t, `SELECT 2, 5, 'e', -1, NULL, NULL`), + ) + }) }) } diff --git a/pkg/ccl/importccl/load.go b/pkg/ccl/importccl/load.go index 4be1b1cf9ff3..503e842a0b0c 100644 --- a/pkg/ccl/importccl/load.go +++ b/pkg/ccl/importccl/load.go @@ -161,6 +161,8 @@ func Load( // only uses txn for resolving FKs and interleaved tables, neither of which // are present here. Ditto for the schema accessor. var txn *client.Txn + // At this point the CREATE statements in the loaded SQL do not + // use the SERIAL type so we need not process SERIAL types here. desc, err := sql.MakeTableDesc(ctx, txn, nil /* vt */, st, s, dbDesc.ID, 0 /* table ID */, ts, privs, affected, nil, &evalCtx) if err != nil { diff --git a/pkg/ccl/importccl/read_import_mysql.go b/pkg/ccl/importccl/read_import_mysql.go index 06eb3c5c652c..a78f39dd9ff1 100644 --- a/pkg/ccl/importccl/read_import_mysql.go +++ b/pkg/ccl/importccl/read_import_mysql.go @@ -304,6 +304,12 @@ func mysqlTableToCockroach( if err != nil { return nil, nil, err } + // The new types in the table imported from MySQL do not (yet?) + // use SERIAL so we need not process SERIAL types here. + // + // If/when we extend this functionality to support MySQL'sAUTO + // INCREMENT, this will need to be extended -- see the comments on + // MakeColumnDefDescs(). col, _, _, err := sqlbase.MakeColumnDefDescs(def, &tree.SemaContext{}, evalCtx) if err != nil { return nil, nil, err diff --git a/pkg/sql/alter_table.go b/pkg/sql/alter_table.go index 676ef4e4fdd9..91f3ea76e894 100644 --- a/pkg/sql/alter_table.go +++ b/pkg/sql/alter_table.go @@ -115,6 +115,18 @@ func (n *alterTableNode) startExec(params runParams) error { return pgerror.Unimplemented( "alter add fk", "adding a REFERENCES constraint via ALTER not supported") } + + newDef, seqDbDesc, seqName, seqOpts, err := params.p.processSerialInColumnDef(params.ctx, d, tn) + if err != nil { + return err + } + if seqName != nil { + if err := doCreateSequence(params, n.n.String(), seqDbDesc, seqName, seqOpts); err != nil { + return err + } + } + d = newDef + col, idx, expr, err := sqlbase.MakeColumnDefDescs(d, ¶ms.p.semaCtx, params.EvalContext()) if err != nil { return err diff --git a/pkg/sql/coltypes/aliases.go b/pkg/sql/coltypes/aliases.go index 31cb0bfddc47..9538b61a880b 100644 --- a/pkg/sql/coltypes/aliases.go +++ b/pkg/sql/coltypes/aliases.go @@ -51,10 +51,6 @@ var ( Serial4 = &TInt{Name: "SERIAL4"} // Serial8 is an immutable T instance. Serial8 = &TInt{Name: "SERIAL8"} - // SmallSerial is an immutable T instance. - SmallSerial = &TInt{Name: "SMALLSERIAL"} - // BigSerial is an immutable T instance. - BigSerial = &TInt{Name: "BIGSERIAL"} // Real is an immutable T instance. Real = &TFloat{Name: "REAL", Width: 32} diff --git a/pkg/sql/coltypes/arith.go b/pkg/sql/coltypes/arith.go index 2b8a32896717..b18ef0ba3c6f 100644 --- a/pkg/sql/coltypes/arith.go +++ b/pkg/sql/coltypes/arith.go @@ -53,12 +53,10 @@ func (node *TInt) Format(buf *bytes.Buffer, f lex.EncodeFlags) { } var serialIntTypes = map[string]struct{}{ - SmallSerial.Name: {}, - Serial.Name: {}, - BigSerial.Name: {}, - Serial2.Name: {}, - Serial4.Name: {}, - Serial8.Name: {}, + Serial.Name: {}, + Serial2.Name: {}, + Serial4.Name: {}, + Serial8.Name: {}, } // IsSerial returns true when this column should be given a DEFAULT of a unique, diff --git a/pkg/sql/conn_executor.go b/pkg/sql/conn_executor.go index 23be39b9334f..6194918131dc 100644 --- a/pkg/sql/conn_executor.go +++ b/pkg/sql/conn_executor.go @@ -441,14 +441,15 @@ func (sp sessionParams) sessionData( curDb = sessiondata.DefaultDatabaseName } sd := sessiondata.SessionData{ - ApplicationName: sp.args.ApplicationName, - Database: curDb, - DistSQLMode: sessiondata.DistSQLExecMode(DistSQLClusterExecMode.Get(&settings.SV)), - OptimizerMode: sessiondata.OptimizerMode(OptimizerClusterMode.Get(&settings.SV)), - SearchPath: sqlbase.DefaultSearchPath, - User: sp.args.User, - RemoteAddr: sp.args.RemoteAddr, - SequenceState: sessiondata.NewSequenceState(), + ApplicationName: sp.args.ApplicationName, + Database: curDb, + DistSQLMode: sessiondata.DistSQLExecMode(DistSQLClusterExecMode.Get(&settings.SV)), + OptimizerMode: sessiondata.OptimizerMode(OptimizerClusterMode.Get(&settings.SV)), + SerialNormalizationMode: sessiondata.SerialNormalizationMode(SerialNormalizationMode.Get(&settings.SV)), + SearchPath: sqlbase.DefaultSearchPath, + User: sp.args.User, + RemoteAddr: sp.args.RemoteAddr, + SequenceState: sessiondata.NewSequenceState(), DataConversion: sessiondata.DataConversionConfig{ Location: time.UTC, }, diff --git a/pkg/sql/create_table.go b/pkg/sql/create_table.go index 5a877f10e87c..866e942cbcce 100644 --- a/pkg/sql/create_table.go +++ b/pkg/sql/create_table.go @@ -142,7 +142,7 @@ func (n *createTableNode) startExec(params runParams) error { privs, ¶ms.p.semaCtx, params.EvalContext()) } else { affected = make(map[sqlbase.ID]*sqlbase.TableDescriptor) - desc, err = params.p.makeTableDesc(params.ctx, n.n, n.dbDesc.ID, id, creationTime, privs, affected) + desc, err = makeTableDesc(params, n.n, n.dbDesc.ID, id, creationTime, privs, affected) } if err != nil { return err @@ -946,6 +946,8 @@ func makeTableDescIfAs( columnTableDef.Name = p.AsColumnNames[i] } + // The new types in the CREATE TABLE AS column specs never use + // SERIAL so we need not process SERIAL types here. col, _, _, err := sqlbase.MakeColumnDefDescs(&columnTableDef, semaCtx, evalCtx) if err != nil { return desc, err @@ -1005,6 +1007,11 @@ func dequalifyColumnRefs( // to bypass caching and enable visibility of just-added descriptors. // This is used to resolve sequence and FK dependencies. Also see the // comment at the start of the global scope resolveFK(). +// +// If the table definition *may* use the SERIAL type, the caller is +// also responsible for processing serial types using +// processSerialInColumnDef() on every column definition, and creating +// the necessary sequences in KV before calling MakeTableDesc(). func MakeTableDesc( ctx context.Context, txn *client.Txn, @@ -1253,32 +1260,66 @@ func MakeTableDesc( } // makeTableDesc creates a table descriptor from a CreateTable statement. -func (p *planner) makeTableDesc( - ctx context.Context, +func makeTableDesc( + params runParams, n *tree.CreateTable, parentID, id sqlbase.ID, creationTime hlc.Timestamp, privileges *sqlbase.PrivilegeDescriptor, affected map[sqlbase.ID]*sqlbase.TableDescriptor, ) (ret sqlbase.TableDescriptor, err error) { + tableName, err := n.Table.Normalize() + if err != nil { + return ret, err + } + // Process any SERIAL columns to remove the SERIAL type, + // as required by MakeTableDesc. + createStmt := n + ensureCopy := func() { + if createStmt == n { + newCreateStmt := *n + n.Defs = append(tree.TableDefs(nil), n.Defs...) + createStmt = &newCreateStmt + } + } + for i, def := range n.Defs { + d, ok := def.(*tree.ColumnTableDef) + if !ok { + continue + } + newDef, seqDbDesc, seqName, seqOpts, err := params.p.processSerialInColumnDef(params.ctx, d, tableName) + if err != nil { + return ret, err + } + if seqName != nil { + if err := doCreateSequence(params, n.String(), seqDbDesc, seqName, seqOpts); err != nil { + return ret, err + } + } + if d != newDef { + ensureCopy() + n.Defs[i] = newDef + } + } + // We need to run MakeTableDesc with caching disabled, because // it needs to pull in descriptors from FK depended-on tables // and interleaved parents using their current state in KV. // See the comment at the start of MakeTableDesc() and resolveFK(). - p.runWithOptions(resolveFlags{skipCache: true}, func() { + params.p.runWithOptions(resolveFlags{skipCache: true}, func() { ret, err = MakeTableDesc( - ctx, - p.txn, - p, - p.ExecCfg().Settings, + params.ctx, + params.p.txn, + params.p, + params.p.ExecCfg().Settings, n, parentID, id, creationTime, privileges, affected, - &p.semaCtx, - p.EvalContext(), + ¶ms.p.semaCtx, + params.p.EvalContext(), ) }) return ret, err diff --git a/pkg/sql/create_view.go b/pkg/sql/create_view.go index 526fe45a1a5e..730cec0155a7 100644 --- a/pkg/sql/create_view.go +++ b/pkg/sql/create_view.go @@ -228,6 +228,8 @@ func (n *createViewNode) makeViewTableDesc( if len(columnNames) > i { columnTableDef.Name = columnNames[i] } + // The new types in the CREATE VIEW column specs never use + // SERIAL so we need not process SERIAL types here. col, _, _, err := sqlbase.MakeColumnDefDescs( &columnTableDef, ¶ms.p.semaCtx, params.EvalContext()) if err != nil { diff --git a/pkg/sql/exec_util.go b/pkg/sql/exec_util.go index c540f4ecad8d..f30211b95586 100644 --- a/pkg/sql/exec_util.go +++ b/pkg/sql/exec_util.go @@ -125,6 +125,19 @@ var DistSQLClusterExecMode = settings.RegisterEnumSetting( }, ) +// SerialNormalizationMode controls how the SERIAL type is interpreted in table +// definitions. +var SerialNormalizationMode = settings.RegisterEnumSetting( + "sql.defaults.serial_normalization", + "default handling of SERIAL in table definitions", + "rowid", + map[int64]string{ + int64(sessiondata.SerialUsesRowID): "rowid", + int64(sessiondata.SerialUsesVirtualSequences): "virtual_sequence", + int64(sessiondata.SerialUsesSQLSequences): "sql_sequence", + }, +) + var errNoTransactionInProgress = errors.New("there is no transaction in progress") var errTransactionInProgress = errors.New("there is already a transaction in progress") @@ -1560,6 +1573,10 @@ func (m *sessionDataMutator) SetOptimizerMode(val sessiondata.OptimizerMode) { m.data.OptimizerMode = val } +func (m *sessionDataMutator) SetSerialNormalizationMode(val sessiondata.SerialNormalizationMode) { + m.data.SerialNormalizationMode = val +} + func (m *sessionDataMutator) SetSafeUpdates(val bool) { m.data.SafeUpdates = val } diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog index f8ef088f20b7..9417b21007e2 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_catalog +++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog @@ -1265,108 +1265,111 @@ SET DATABASE = test query TTTTTT colnames SELECT name, setting, category, short_desc, extra_desc, vartype FROM pg_catalog.pg_settings WHERE name != 'experimental_opt' ---- -name setting category short_desc extra_desc vartype -application_name · NULL NULL NULL string -bytea_output hex NULL NULL NULL string -client_encoding UTF8 NULL NULL NULL string -client_min_messages notice NULL NULL NULL string -database test NULL NULL NULL string -datestyle ISO NULL NULL NULL string -default_transaction_isolation serializable NULL NULL NULL string -default_transaction_read_only off NULL NULL NULL string -distsql off NULL NULL NULL string -experimental_force_lookup_join off NULL NULL NULL string -experimental_force_zigzag_join off NULL NULL NULL string -extra_float_digits 0 NULL NULL NULL string -integer_datetimes on NULL NULL NULL string -intervalstyle postgres NULL NULL NULL string -max_index_keys 32 NULL NULL NULL string -node_id 1 NULL NULL NULL string -search_path public NULL NULL NULL string -server_encoding UTF8 NULL NULL NULL string -server_version 9.5.0 NULL NULL NULL string -server_version_num 90500 NULL NULL NULL string -session_user root NULL NULL NULL string -sql_safe_updates false NULL NULL NULL string -standard_conforming_strings on NULL NULL NULL string -statement_timeout 0s NULL NULL NULL string -timezone UTC NULL NULL NULL string -tracing off NULL NULL NULL string -transaction_isolation serializable NULL NULL NULL string -transaction_priority normal NULL NULL NULL string -transaction_read_only off NULL NULL NULL string -transaction_status NoTxn NULL NULL NULL string +name setting category short_desc extra_desc vartype +application_name · NULL NULL NULL string +bytea_output hex NULL NULL NULL string +client_encoding UTF8 NULL NULL NULL string +client_min_messages notice NULL NULL NULL string +database test NULL NULL NULL string +datestyle ISO NULL NULL NULL string +default_transaction_isolation serializable NULL NULL NULL string +default_transaction_read_only off NULL NULL NULL string +distsql off NULL NULL NULL string +experimental_force_lookup_join off NULL NULL NULL string +experimental_force_zigzag_join off NULL NULL NULL string +experimental_serial_normalization rowid NULL NULL NULL string +extra_float_digits 0 NULL NULL NULL string +integer_datetimes on NULL NULL NULL string +intervalstyle postgres NULL NULL NULL string +max_index_keys 32 NULL NULL NULL string +node_id 1 NULL NULL NULL string +search_path public NULL NULL NULL string +server_encoding UTF8 NULL NULL NULL string +server_version 9.5.0 NULL NULL NULL string +server_version_num 90500 NULL NULL NULL string +session_user root NULL NULL NULL string +sql_safe_updates false NULL NULL NULL string +standard_conforming_strings on NULL NULL NULL string +statement_timeout 0s NULL NULL NULL string +timezone UTC NULL NULL NULL string +tracing off NULL NULL NULL string +transaction_isolation serializable NULL NULL NULL string +transaction_priority normal NULL NULL NULL string +transaction_read_only off NULL NULL NULL string +transaction_status NoTxn NULL NULL NULL string query TTTTTTT colnames SELECT name, setting, unit, context, enumvals, boot_val, reset_val FROM pg_catalog.pg_settings WHERE name != 'experimental_opt' ---- -name setting unit context enumvals boot_val reset_val -application_name · NULL user NULL · · -bytea_output hex NULL user NULL hex hex -client_encoding UTF8 NULL user NULL UTF8 UTF8 -client_min_messages notice NULL user NULL notice notice -database test NULL user NULL test test -datestyle ISO NULL user NULL ISO ISO -default_transaction_isolation serializable NULL user NULL serializable serializable -default_transaction_read_only off NULL user NULL off off -distsql off NULL user NULL off off -experimental_force_lookup_join off NULL user NULL off off -experimental_force_zigzag_join off NULL user NULL off off -extra_float_digits 0 NULL user NULL 0 0 -integer_datetimes on NULL user NULL on on -intervalstyle postgres NULL user NULL postgres postgres -max_index_keys 32 NULL user NULL 32 32 -node_id 1 NULL user NULL 1 1 -search_path public NULL user NULL public public -server_encoding UTF8 NULL user NULL UTF8 UTF8 -server_version 9.5.0 NULL user NULL 9.5.0 9.5.0 -server_version_num 90500 NULL user NULL 90500 90500 -session_user root NULL user NULL root root -sql_safe_updates false NULL user NULL false false -standard_conforming_strings on NULL user NULL on on -statement_timeout 0s NULL user NULL 0s 0s -timezone UTC NULL user NULL UTC UTC -tracing off NULL user NULL off off -transaction_isolation serializable NULL user NULL serializable serializable -transaction_priority normal NULL user NULL normal normal -transaction_read_only off NULL user NULL off off -transaction_status NoTxn NULL user NULL NoTxn NoTxn +name setting unit context enumvals boot_val reset_val +application_name · NULL user NULL · · +bytea_output hex NULL user NULL hex hex +client_encoding UTF8 NULL user NULL UTF8 UTF8 +client_min_messages notice NULL user NULL notice notice +database test NULL user NULL test test +datestyle ISO NULL user NULL ISO ISO +default_transaction_isolation serializable NULL user NULL serializable serializable +default_transaction_read_only off NULL user NULL off off +distsql off NULL user NULL off off +experimental_force_lookup_join off NULL user NULL off off +experimental_force_zigzag_join off NULL user NULL off off +experimental_serial_normalization rowid NULL user NULL rowid rowid +extra_float_digits 0 NULL user NULL 0 0 +integer_datetimes on NULL user NULL on on +intervalstyle postgres NULL user NULL postgres postgres +max_index_keys 32 NULL user NULL 32 32 +node_id 1 NULL user NULL 1 1 +search_path public NULL user NULL public public +server_encoding UTF8 NULL user NULL UTF8 UTF8 +server_version 9.5.0 NULL user NULL 9.5.0 9.5.0 +server_version_num 90500 NULL user NULL 90500 90500 +session_user root NULL user NULL root root +sql_safe_updates false NULL user NULL false false +standard_conforming_strings on NULL user NULL on on +statement_timeout 0s NULL user NULL 0s 0s +timezone UTC NULL user NULL UTC UTC +tracing off NULL user NULL off off +transaction_isolation serializable NULL user NULL serializable serializable +transaction_priority normal NULL user NULL normal normal +transaction_read_only off NULL user NULL off off +transaction_status NoTxn NULL user NULL NoTxn NoTxn query TTTTTT colnames SELECT name, source, min_val, max_val, sourcefile, sourceline FROM pg_catalog.pg_settings ---- -name source min_val max_val sourcefile sourceline -application_name NULL NULL NULL NULL NULL -bytea_output NULL NULL NULL NULL NULL -client_encoding NULL NULL NULL NULL NULL -client_min_messages NULL NULL NULL NULL NULL -database NULL NULL NULL NULL NULL -datestyle NULL NULL NULL NULL NULL -default_transaction_isolation NULL NULL NULL NULL NULL -default_transaction_read_only NULL NULL NULL NULL NULL -distsql NULL NULL NULL NULL NULL -experimental_force_lookup_join NULL NULL NULL NULL NULL -experimental_force_zigzag_join NULL NULL NULL NULL NULL -experimental_opt NULL NULL NULL NULL NULL -extra_float_digits NULL NULL NULL NULL NULL -integer_datetimes NULL NULL NULL NULL NULL -intervalstyle NULL NULL NULL NULL NULL -max_index_keys NULL NULL NULL NULL NULL -node_id NULL NULL NULL NULL NULL -search_path NULL NULL NULL NULL NULL -server_encoding NULL NULL NULL NULL NULL -server_version NULL NULL NULL NULL NULL -server_version_num NULL NULL NULL NULL NULL -session_user NULL NULL NULL NULL NULL -sql_safe_updates NULL NULL NULL NULL NULL -standard_conforming_strings NULL NULL NULL NULL NULL -statement_timeout NULL NULL NULL NULL NULL -timezone NULL NULL NULL NULL NULL -tracing NULL NULL NULL NULL NULL -transaction_isolation NULL NULL NULL NULL NULL -transaction_priority NULL NULL NULL NULL NULL -transaction_read_only NULL NULL NULL NULL NULL -transaction_status NULL NULL NULL NULL NULL +name source min_val max_val sourcefile sourceline +application_name NULL NULL NULL NULL NULL +bytea_output NULL NULL NULL NULL NULL +client_encoding NULL NULL NULL NULL NULL +client_min_messages NULL NULL NULL NULL NULL +database NULL NULL NULL NULL NULL +datestyle NULL NULL NULL NULL NULL +default_transaction_isolation NULL NULL NULL NULL NULL +default_transaction_read_only NULL NULL NULL NULL NULL +distsql NULL NULL NULL NULL NULL +experimental_force_lookup_join NULL NULL NULL NULL NULL +experimental_force_zigzag_join NULL NULL NULL NULL NULL +experimental_opt NULL NULL NULL NULL NULL +experimental_serial_normalization NULL NULL NULL NULL NULL +extra_float_digits NULL NULL NULL NULL NULL +integer_datetimes NULL NULL NULL NULL NULL +intervalstyle NULL NULL NULL NULL NULL +max_index_keys NULL NULL NULL NULL NULL +node_id NULL NULL NULL NULL NULL +search_path NULL NULL NULL NULL NULL +server_encoding NULL NULL NULL NULL NULL +server_version NULL NULL NULL NULL NULL +server_version_num NULL NULL NULL NULL NULL +session_user NULL NULL NULL NULL NULL +sql_safe_updates NULL NULL NULL NULL NULL +standard_conforming_strings NULL NULL NULL NULL NULL +statement_timeout NULL NULL NULL NULL NULL +timezone NULL NULL NULL NULL NULL +tracing NULL NULL NULL NULL NULL +transaction_isolation NULL NULL NULL NULL NULL +transaction_priority NULL NULL NULL NULL NULL +transaction_read_only NULL NULL NULL NULL NULL +transaction_status NULL NULL NULL NULL NULL # pg_catalog.pg_sequence diff --git a/pkg/sql/logictest/testdata/logic_test/serial b/pkg/sql/logictest/testdata/logic_test/serial index 0f1fd04b332d..cd94e49a6de9 100644 --- a/pkg/sql/logictest/testdata/logic_test/serial +++ b/pkg/sql/logictest/testdata/logic_test/serial @@ -1,5 +1,7 @@ # LogicTest: local local-opt local-parallel-stmts fakedist fakedist-opt fakedist-metadata +subtest serial_rowid + statement ok CREATE TABLE serial ( a SERIAL PRIMARY KEY, @@ -8,6 +10,18 @@ CREATE TABLE serial ( UNIQUE INDEX (c) ) +query TT +SHOW CREATE TABLE serial +---- +serial CREATE TABLE serial ( + a INT NOT NULL DEFAULT unique_rowid(), + b INT NULL DEFAULT 7:::INT, + c INT NOT NULL DEFAULT unique_rowid(), + CONSTRAINT "primary" PRIMARY KEY (a ASC), + UNIQUE INDEX serial_c_key (c ASC), + FAMILY "primary" (a, b, c) +) + statement ok INSERT INTO serial (a, b) VALUES (1, 2), (DEFAULT, DEFAULT), (DEFAULT, 3) @@ -19,15 +33,28 @@ SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM serial ---- 4 3 4 -statement error SERIAL column \"a\" cannot have a default value +statement error multiple default values specified for column "a" of table "s1" CREATE TABLE s1 (a SERIAL DEFAULT 7) +statement error conflicting NULL/NOT NULL declarations for column "a" of table "s1" +CREATE TABLE s1 (a SERIAL NULL) + statement ok CREATE TABLE smallbig (a SMALLSERIAL, b BIGSERIAL, c INT) statement ok INSERT INTO smallbig (c) VALUES (7), (7) +query TT +SHOW CREATE TABLE smallbig +---- +smallbig CREATE TABLE smallbig ( + a INT NOT NULL DEFAULT unique_rowid(), + b INT NOT NULL DEFAULT unique_rowid(), + c INT NULL, + FAMILY "primary" (a, b, c, rowid) +) + query III SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM smallbig ---- @@ -36,6 +63,17 @@ SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM smallbig statement ok CREATE TABLE serials (a SERIAL2, b SERIAL4, c SERIAL8, d INT) +query TT +SHOW CREATE TABLE serials +---- +serials CREATE TABLE serials ( + a INT NOT NULL DEFAULT unique_rowid(), + b INT NOT NULL DEFAULT unique_rowid(), + c INT NOT NULL DEFAULT unique_rowid(), + d INT NULL, + FAMILY "primary" (a, b, c, d, rowid) +) + statement ok INSERT INTO serials (d) VALUES (9), (9) @@ -43,3 +81,198 @@ query III SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM serials ---- 2 2 2 + +statement ok +DROP TABLE serials, smallbig, serial + + +subtest serial_virtual_sequence + +statement ok +SET experimental_serial_normalization = virtual_sequence + +# Force the sequence for column "c" to bump to 2. +statement ok +CREATE SEQUENCE serial_c_seq; CREATE SEQUENCE serial_c_seq1 + +statement ok +CREATE TABLE serial ( + a SERIAL PRIMARY KEY, + b INT DEFAULT 7, + c SERIAL, + UNIQUE INDEX (c) +) + +query TT +SHOW CREATE TABLE serial +---- +serial CREATE TABLE serial ( + a INT NOT NULL DEFAULT nextval('serial_a_seq':::STRING), + b INT NULL DEFAULT 7:::INT, + c INT NOT NULL DEFAULT nextval('serial_c_seq2':::STRING), + CONSTRAINT "primary" PRIMARY KEY (a ASC), + UNIQUE INDEX serial_c_key (c ASC), + FAMILY "primary" (a, b, c) +) + +query TT +SHOW CREATE SEQUENCE serial_a_seq +---- +serial_a_seq CREATE SEQUENCE serial_a_seq MINVALUE 1 MAXVALUE 9223372036854775807 INCREMENT 1 START 1 VIRTUAL + +statement ok +INSERT INTO serial (a, b) VALUES (1, 2), (DEFAULT, DEFAULT), (DEFAULT, 3) + +statement ok +INSERT INTO serial (b) VALUES (2) + +query III +SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM serial +---- +4 3 4 + +statement error multiple default values specified for column "a" of table "s1" +CREATE TABLE s1 (a SERIAL DEFAULT 7) + +statement error conflicting NULL/NOT NULL declarations for column "a" of table "s1" +CREATE TABLE s1 (a SERIAL NULL) + +statement ok +CREATE TABLE smallbig (a SMALLSERIAL, b BIGSERIAL, c INT) + +statement ok +INSERT INTO smallbig (c) VALUES (7), (7) + +query TT +SHOW CREATE TABLE smallbig +---- +smallbig CREATE TABLE smallbig ( + a INT NOT NULL DEFAULT nextval('smallbig_a_seq':::STRING), + b INT NOT NULL DEFAULT nextval('smallbig_b_seq':::STRING), + c INT NULL, + FAMILY "primary" (a, b, c, rowid) +) + +query III +SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM smallbig +---- +2 2 1 + +statement ok +CREATE TABLE serials (a SERIAL2, b SERIAL4, c SERIAL8, d INT) + +query TT +SHOW CREATE TABLE serials +---- +serials CREATE TABLE serials ( + a INT NOT NULL DEFAULT nextval('serials_a_seq':::STRING), + b INT NOT NULL DEFAULT nextval('serials_b_seq':::STRING), + c INT NOT NULL DEFAULT nextval('serials_c_seq':::STRING), + d INT NULL, + FAMILY "primary" (a, b, c, d, rowid) +) + +statement ok +INSERT INTO serials (d) VALUES (9), (9) + +query III +SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM serials +---- +2 2 2 + +statement ok +DROP TABLE serials, smallbig, serial + + +subtest serial_sql_sequence + +statement ok +SET experimental_serial_normalization = sql_sequence + +statement ok +CREATE TABLE serial ( + a SERIAL PRIMARY KEY, + b INT DEFAULT 7, + c SERIAL, + UNIQUE INDEX (c) +) + +query TT +SHOW CREATE TABLE serial +---- +serial CREATE TABLE serial ( + a INTEGER NOT NULL DEFAULT nextval('serial_a_seq1':::STRING), + b INT NULL DEFAULT 7:::INT, + c INTEGER NOT NULL DEFAULT nextval('serial_c_seq3':::STRING), + CONSTRAINT "primary" PRIMARY KEY (a ASC), + UNIQUE INDEX serial_c_key (c ASC), + FAMILY "primary" (a, b, c) +) + +query TT +SHOW CREATE SEQUENCE serial_a_seq1 +---- +serial_a_seq1 CREATE SEQUENCE serial_a_seq1 MINVALUE 1 MAXVALUE 9223372036854775807 INCREMENT 1 START 1 + +statement ok +INSERT INTO serial (a, b) VALUES (0, 2), (DEFAULT, DEFAULT), (DEFAULT, 3) + +statement ok +INSERT INTO serial (b) VALUES (2) + +query III +SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM serial +---- +4 3 4 + +statement error multiple default values specified for column "a" of table "s1" +CREATE TABLE s1 (a SERIAL DEFAULT 7) + +statement error conflicting NULL/NOT NULL declarations for column "a" of table "s1" +CREATE TABLE s1 (a SERIAL NULL) + +statement ok +CREATE TABLE smallbig (a SMALLSERIAL, b BIGSERIAL, c INT) + +statement ok +INSERT INTO smallbig (c) VALUES (7), (7) + +query TT +SHOW CREATE TABLE smallbig +---- +smallbig CREATE TABLE smallbig ( + a SMALLINT NOT NULL DEFAULT nextval('smallbig_a_seq1':::STRING), + b BIGINT NOT NULL DEFAULT nextval('smallbig_b_seq1':::STRING), + c INT NULL, + FAMILY "primary" (a, b, c, rowid) +) + +query III +SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM smallbig +---- +2 2 1 + +statement ok +CREATE TABLE serials (a SERIAL2, b SERIAL4, c SERIAL8, d INT) + +query TT +SHOW CREATE TABLE serials +---- +serials CREATE TABLE serials ( + a SMALLINT NOT NULL DEFAULT nextval('serials_a_seq1':::STRING), + b INTEGER NOT NULL DEFAULT nextval('serials_b_seq1':::STRING), + c BIGINT NOT NULL DEFAULT nextval('serials_c_seq1':::STRING), + d INT NULL, + FAMILY "primary" (a, b, c, d, rowid) +) + +statement ok +INSERT INTO serials (d) VALUES (9), (9) + +query III +SELECT count(DISTINCT a), count(DISTINCT b), count(DISTINCT c) FROM serials +---- +2 2 2 + +statement ok +DROP TABLE serials, smallbig, serial diff --git a/pkg/sql/logictest/testdata/logic_test/show_source b/pkg/sql/logictest/testdata/logic_test/show_source index 8d743729d953..762c923cf063 100644 --- a/pkg/sql/logictest/testdata/logic_test/show_source +++ b/pkg/sql/logictest/testdata/logic_test/show_source @@ -23,37 +23,38 @@ UTF8 1 query TT colnames SELECT * FROM [SHOW ALL] WHERE variable != 'experimental_opt' ---- -variable value -application_name · -bytea_output hex -client_encoding UTF8 -client_min_messages notice -database test -datestyle ISO -default_transaction_isolation serializable -default_transaction_read_only off -distsql off -experimental_force_lookup_join off -experimental_force_zigzag_join off -extra_float_digits 0 -integer_datetimes on -intervalstyle postgres -max_index_keys 32 -node_id 1 -search_path public -server_encoding UTF8 -server_version 9.5.0 -server_version_num 90500 -session_user root -sql_safe_updates false -standard_conforming_strings on -statement_timeout 0s -timezone UTC -tracing off -transaction_isolation serializable -transaction_priority normal -transaction_read_only off -transaction_status NoTxn +variable value +application_name · +bytea_output hex +client_encoding UTF8 +client_min_messages notice +database test +datestyle ISO +default_transaction_isolation serializable +default_transaction_read_only off +distsql off +experimental_force_lookup_join off +experimental_force_zigzag_join off +experimental_serial_normalization rowid +extra_float_digits 0 +integer_datetimes on +intervalstyle postgres +max_index_keys 32 +node_id 1 +search_path public +server_encoding UTF8 +server_version 9.5.0 +server_version_num 90500 +session_user root +sql_safe_updates false +standard_conforming_strings on +statement_timeout 0s +timezone UTC +tracing off +transaction_isolation serializable +transaction_priority normal +transaction_read_only off +transaction_status NoTxn query I colnames SELECT * FROM [SHOW CLUSTER SETTING sql.defaults.distsql] diff --git a/pkg/sql/logictest/testdata/logic_test/table b/pkg/sql/logictest/testdata/logic_test/table index 6c95afa8f453..57ebf4d970ed 100644 --- a/pkg/sql/logictest/testdata/logic_test/table +++ b/pkg/sql/logictest/testdata/logic_test/table @@ -305,7 +305,10 @@ CREATE TABLE test.dupe_named_constraints ( ) statement ok -CREATE TABLE test.alltypes ( +SET database = test + +statement ok +CREATE TABLE alltypes ( cbigint BIGINT, cbigserial BIGSERIAL, cbit BIT, @@ -351,11 +354,11 @@ CREATE TABLE test.alltypes ( ) query TTBTTT colnames -SHOW COLUMNS FROM test.alltypes +SHOW COLUMNS FROM alltypes ---- column_name data_type is_nullable column_default generation_expression indices cbigint BIGINT true NULL · {} -cbigserial INT true unique_rowid() · {} +cbigserial INT false unique_rowid() · {} cbit BIT(1) true NULL · {} cbit12 BIT(12) true NULL · {} cblob BYTES true NULL · {} @@ -386,9 +389,9 @@ cnumeric DECIMAL true NULL · cnumeric1 DECIMAL(1) true NULL · {} cnumeric21 DECIMAL(2,1) true NULL · {} creal REAL true NULL · {} -cserial INT true unique_rowid() · {} +cserial INT false unique_rowid() · {} csmallint SMALLINT true NULL · {} -csmallserial INT true unique_rowid() · {} +csmallserial INT false unique_rowid() · {} cstring STRING true NULL · {} cstring12 STRING(12) true NULL · {} ctext STRING true NULL · {} diff --git a/pkg/sql/logictest/testdata/planner_test/explain b/pkg/sql/logictest/testdata/planner_test/explain index d715f5e26a17..20680f671b1c 100644 --- a/pkg/sql/logictest/testdata/planner_test/explain +++ b/pkg/sql/logictest/testdata/planner_test/explain @@ -167,7 +167,7 @@ EXPLAIN SHOW DATABASE render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW TIME ZONE @@ -175,7 +175,7 @@ EXPLAIN SHOW TIME ZONE render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW DEFAULT_TRANSACTION_ISOLATION @@ -183,7 +183,7 @@ EXPLAIN SHOW DEFAULT_TRANSACTION_ISOLATION render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW TRANSACTION ISOLATION LEVEL @@ -191,7 +191,7 @@ EXPLAIN SHOW TRANSACTION ISOLATION LEVEL render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW TRANSACTION PRIORITY @@ -199,7 +199,7 @@ EXPLAIN SHOW TRANSACTION PRIORITY render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW COLUMNS FROM foo diff --git a/pkg/sql/opt/exec/execbuilder/testdata/explain b/pkg/sql/opt/exec/execbuilder/testdata/explain index 23680588c8ee..c8d6a4a61214 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/explain +++ b/pkg/sql/opt/exec/execbuilder/testdata/explain @@ -160,7 +160,7 @@ EXPLAIN SHOW DATABASE render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW TIME ZONE @@ -168,7 +168,7 @@ EXPLAIN SHOW TIME ZONE render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW DEFAULT_TRANSACTION_ISOLATION @@ -176,7 +176,7 @@ EXPLAIN SHOW DEFAULT_TRANSACTION_ISOLATION render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW TRANSACTION ISOLATION LEVEL @@ -184,7 +184,7 @@ EXPLAIN SHOW TRANSACTION ISOLATION LEVEL render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW TRANSACTION PRIORITY @@ -192,7 +192,7 @@ EXPLAIN SHOW TRANSACTION PRIORITY render · · └── filter · · └── values · · -· size 2 columns, 31 rows +· size 2 columns, 32 rows query TTT EXPLAIN SHOW COLUMNS FROM foo diff --git a/pkg/sql/parser/parse_test.go b/pkg/sql/parser/parse_test.go index a5458d64f177..54299c65dad4 100644 --- a/pkg/sql/parser/parse_test.go +++ b/pkg/sql/parser/parse_test.go @@ -99,8 +99,6 @@ func TestParse(t *testing.T) { {`CREATE TABLE a (b STRING(3))`}, {`CREATE TABLE a (b FLOAT)`}, {`CREATE TABLE a (b SERIAL)`}, - {`CREATE TABLE a (b SMALLSERIAL)`}, - {`CREATE TABLE a (b BIGSERIAL)`}, {`CREATE TABLE a (b TIME)`}, {`CREATE TABLE a (b UUID)`}, {`CREATE TABLE a (b INET)`}, @@ -1110,6 +1108,9 @@ func TestParse2(t *testing.T) { `CREATE TABLE a (UNIQUE (b) PARTITION BY LIST (c) (PARTITION d VALUES IN (1)))`}, {`CREATE INDEX ON a (b) COVERING (c)`, `CREATE INDEX ON a (b) STORING (c)`}, + {`CREATE TABLE a (b BIGSERIAL, c SMALLSERIAL)`, + `CREATE TABLE a (b SERIAL8, c SERIAL2)`}, + {`SELECT TIMESTAMP WITHOUT TIME ZONE 'foo'`, `SELECT TIMESTAMP 'foo'`}, {`SELECT CAST('foo' AS TIMESTAMP WITHOUT TIME ZONE)`, `SELECT CAST('foo' AS TIMESTAMP)`}, {`SELECT CAST(1 AS "char")`, `SELECT CAST(1 AS CHAR)`}, diff --git a/pkg/sql/parser/sql.y b/pkg/sql/parser/sql.y index f8449f9235cc..b855f64e61bb 100644 --- a/pkg/sql/parser/sql.y +++ b/pkg/sql/parser/sql.y @@ -5932,7 +5932,7 @@ const_typename: } | SMALLSERIAL { - $$.val = coltypes.SmallSerial + $$.val = coltypes.Serial2 } | UUID { @@ -5944,7 +5944,7 @@ const_typename: } | BIGSERIAL { - $$.val = coltypes.BigSerial + $$.val = coltypes.Serial8 } | OID { diff --git a/pkg/sql/sem/tree/create.go b/pkg/sql/sem/tree/create.go index f88925e46d40..4515811853db 100644 --- a/pkg/sql/sem/tree/create.go +++ b/pkg/sql/sem/tree/create.go @@ -433,6 +433,9 @@ func (node *ColumnTableDef) Format(ctx *FmtCtx) { } } +// String implements the fmt.Stringer interface. +func (node *ColumnTableDef) String() string { return AsString(node) } + // NamedColumnQualification wraps a NamedColumnQualification with a name. type NamedColumnQualification struct { Name Name diff --git a/pkg/sql/serial.go b/pkg/sql/serial.go new file mode 100644 index 000000000000..ea7a9094fba7 --- /dev/null +++ b/pkg/sql/serial.go @@ -0,0 +1,215 @@ +// Copyright 2018 The Cockroach Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. See the License for the specific language governing +// permissions and limitations under the License. + +package sql + +import ( + "context" + "fmt" + + "github.com/cockroachdb/cockroach/pkg/sql/coltypes" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" + "github.com/cockroachdb/cockroach/pkg/util/log" +) + +// uniqueRowIDExpr is used as default expression when +// SessionNormalizationMode is SerialUsesRowID. +var uniqueRowIDExpr = &tree.FuncExpr{Func: tree.WrapFunction("unique_rowid")} + +// realSequenceOpts (nil) is used when SessionNormalizationMode is +// SerialUsesSQLSequences. +var realSequenceOpts tree.SequenceOptions + +// virtualSequenceOpts is used when SessionNormalizationMode is +// SerialUsesVirtualSequences. +var virtualSequenceOpts = tree.SequenceOptions{ + tree.SequenceOption{Name: tree.SeqOptVirtual}, +} + +// processSerialInColumnDef analyzes a column definition and determines +// whether to use a sequence if the requested type is SERIAL-like. +// If a sequence must be created, it returns an ObjectName to use +// to create the new sequence and the DatabaseDescriptor of the +// parent database where it should be created. +// The ColumnTableDef is not mutated in-place; instead a new one is returned. +func (p *planner) processSerialInColumnDef( + ctx context.Context, d *tree.ColumnTableDef, tableName *ObjectName, +) (*tree.ColumnTableDef, *DatabaseDescriptor, *ObjectName, tree.SequenceOptions, error) { + t, ok := d.Type.(*coltypes.TInt) + if !ok || !t.IsSerial() { + // Column is not SERIAL: nothing to do. + return d, nil, nil, nil, nil + } + + if err := assertValidSerialColumnDef(d, tableName); err != nil { + return nil, nil, nil, nil, err + } + + newSpec := *d + + // Make the column non-nullable in all cases. PostgreSQL requires + // this. + newSpec.Nullable.Nullability = tree.NotNull + + serialNormalizationMode := p.SessionData().SerialNormalizationMode + + // Find the integer type that corresponds to the specification. + switch serialNormalizationMode { + case sessiondata.SerialUsesRowID, sessiondata.SerialUsesVirtualSequences: + // If unique_rowid() or virtual sequences are requested, we have + // no choice but to use the full-width integer type, no matter + // which serial size was requested, otherwise the values will not fit. + // + // TODO(knz): change this to coltypes.Int8 when #28690 moves + // forward. + newSpec.Type = coltypes.Int + + case sessiondata.SerialUsesSQLSequences: + // With real sequences we can use exactly the requested type. + switch t.Name { + case coltypes.Serial.Name: + newSpec.Type = coltypes.Integer + case coltypes.Serial2.Name: + newSpec.Type = coltypes.Int2 + case coltypes.Serial4.Name: + newSpec.Type = coltypes.Int4 + case coltypes.Serial8.Name: + newSpec.Type = coltypes.Int8 + } + } + + if serialNormalizationMode == sessiondata.SerialUsesRowID { + // We're not constructing a sequence for this SERIAL column. + // Use the "old school" CockroachDB default. + newSpec.DefaultExpr.Expr = uniqueRowIDExpr + return &newSpec, nil, nil, nil, nil + } + + log.VEventf(ctx, 2, "creating sequence for new column %q of %q", d, tableName) + + // We want a sequence; for this we need to generate a new sequence name. + // The constraint on the name is that an object of this name must not exist already. + seqName := tree.NewUnqualifiedTableName( + tree.Name(tableName.Table() + "_" + string(d.Name) + "_seq")) + + // The first step in the search is to prepare the seqName to fill in + // the catalog/schema parent. This is what ResolveTargetObject does. + // + // Here and below we skip the cache because name resolution using + // the cache does not work (well) if the txn retries and the + // descriptor was written already in an early txn attempt. + var dbDesc *DatabaseDescriptor + var err error + p.runWithOptions(resolveFlags{skipCache: true}, func() { + dbDesc, err = ResolveTargetObject(ctx, p, seqName) + }) + if err != nil { + return nil, nil, nil, nil, err + } + // Now skip over all names that are already taken. + nameBase := seqName.TableName + for i := 0; ; i++ { + if i > 0 { + seqName.TableName = tree.Name(fmt.Sprintf("%s%d", nameBase, i)) + } + var res *ObjectDescriptor + p.runWithOptions(resolveFlags{skipCache: true}, func() { + res, err = ResolveExistingObject(ctx, p, seqName, false /*required*/, anyDescType) + }) + if err != nil { + return nil, nil, nil, nil, err + } + if res == nil { + break + } + } + + defaultExpr := &tree.FuncExpr{ + Func: tree.WrapFunction("nextval"), + Exprs: tree.Exprs{tree.NewStrVal(seqName.Table())}, + } + + seqType := "" + seqOpts := realSequenceOpts + if serialNormalizationMode == sessiondata.SerialUsesVirtualSequences { + seqType = "virtual " + seqOpts = virtualSequenceOpts + } + log.VEventf(ctx, 2, "new column %q of %q will have %ssequence name %q and default %q", + d, tableName, seqType, seqName, defaultExpr) + + newSpec.DefaultExpr.Expr = defaultExpr + + return &newSpec, dbDesc, seqName, seqOpts, nil +} + +// SimplifySerialInColumnDefWithRowID analyzes a column definition and +// simplifies any use of SERIAL as if SerialNormalizationMode was set +// to SerialUsesRowID. No sequence needs to be created. +// +// This is currently used by bulk I/O import statements which do not +// (yet?) support customization of the SERIAL behavior. +func SimplifySerialInColumnDefWithRowID( + ctx context.Context, d *tree.ColumnTableDef, tableName *ObjectName, +) error { + t, ok := d.Type.(*coltypes.TInt) + if !ok || !t.IsSerial() { + // Column is not SERIAL: nothing to do. + return nil + } + + if err := assertValidSerialColumnDef(d, tableName); err != nil { + return err + } + + // Make the column non-nullable in all cases. PostgreSQL requires + // this. + d.Nullable.Nullability = tree.NotNull + + // We're not constructing a sequence for this SERIAL column. + // Use the "old school" CockroachDB default. + d.Type = coltypes.Int + d.DefaultExpr.Expr = uniqueRowIDExpr + + return nil +} + +func assertValidSerialColumnDef(d *tree.ColumnTableDef, tableName *ObjectName) error { + if d.HasDefaultExpr() { + // SERIAL implies a new default expression, we can't have one to + // start with. This is the error produced by pg in such case. + return pgerror.NewErrorf(pgerror.CodeSyntaxError, + "multiple default values specified for column %q of table %q", + tree.ErrString(&d.Name), tree.ErrString(tableName)) + } + + if d.Nullable.Nullability == tree.Null { + // SERIAL implies a non-NULL column, we can't accept a nullability + // spec. This is the error produced by pg in such case. + return pgerror.NewErrorf(pgerror.CodeSyntaxError, + "conflicting NULL/NOT NULL declarations for column %q of table %q", + tree.ErrString(&d.Name), tree.ErrString(tableName)) + } + + if d.Computed.Expr != nil { + // SERIAL cannot be a computed column. + return pgerror.NewErrorf(pgerror.CodeSyntaxError, + "SERIAL column %q of table %q cannot be computed", + tree.ErrString(&d.Name), tree.ErrString(tableName)) + } + + return nil +} diff --git a/pkg/sql/sessiondata/session_data.go b/pkg/sql/sessiondata/session_data.go index 411f1f35e843..7e31e7bf9ca1 100644 --- a/pkg/sql/sessiondata/session_data.go +++ b/pkg/sql/sessiondata/session_data.go @@ -49,6 +49,8 @@ type SessionData struct { // OptimizerMode indicates whether to use the experimental optimizer for // query planning. OptimizerMode OptimizerMode + // SerialNormalizationMode indicates how to handle the SERIAL pseudo-type. + SerialNormalizationMode SerialNormalizationMode // SearchPath is a list of databases that will be searched for a table name // before the database. Currently, this is used only for SELECTs. // Names in the search path must have been normalized already. @@ -264,3 +266,44 @@ func OptimizerModeFromString(val string) (_ OptimizerMode, ok bool) { return 0, false } } + +// SerialNormalizationMode controls if and when the Executor uses DistSQL. +type SerialNormalizationMode int64 + +const ( + // SerialUsesRowID means use INT NOT NULL DEFAULT unique_rowid(). + SerialUsesRowID SerialNormalizationMode = iota + // SerialUsesVirtualSequences means create a virtual sequence and + // use INT NOT NULL DEFAULT nextval(...). + SerialUsesVirtualSequences + // SerialUsesSQLSequences means create a regular SQL sequence and + // use INT NOT NULL DEFAULT nextval(...). + SerialUsesSQLSequences +) + +func (m SerialNormalizationMode) String() string { + switch m { + case SerialUsesRowID: + return "rowid" + case SerialUsesVirtualSequences: + return "virtual_sequence" + case SerialUsesSQLSequences: + return "sql_sequence" + default: + return fmt.Sprintf("invalid (%d)", m) + } +} + +// SerialNormalizationModeFromString converts a string into a SerialNormalizationMode +func SerialNormalizationModeFromString(val string) (_ SerialNormalizationMode, ok bool) { + switch strings.ToUpper(val) { + case "ROWID": + return SerialUsesRowID, true + case "VIRTUAL_SEQUENCE": + return SerialUsesVirtualSequences, true + case "SQL_SEQUENCE": + return SerialUsesSQLSequences, true + default: + return 0, false + } +} diff --git a/pkg/sql/sqlbase/structured_test.go b/pkg/sql/sqlbase/structured_test.go index a722cd50988f..8365f536fb06 100644 --- a/pkg/sql/sqlbase/structured_test.go +++ b/pkg/sql/sqlbase/structured_test.go @@ -1319,10 +1319,10 @@ func TestKeysPerRow(t *testing.T) { indexID IndexID expected int }{ - {"(a SERIAL PRIMARY KEY, b INT, INDEX (b))", 1, 1}, // Primary index - {"(a SERIAL PRIMARY KEY, b INT, INDEX (b))", 2, 1}, // 'b' index - {"(a SERIAL PRIMARY KEY, b INT, FAMILY (a), FAMILY (b), INDEX (b))", 1, 2}, // Primary index - {"(a SERIAL PRIMARY KEY, b INT, FAMILY (a), FAMILY (b), INDEX (b))", 2, 1}, // 'b' index + {"(a INT PRIMARY KEY, b INT, INDEX (b))", 1, 1}, // Primary index + {"(a INT PRIMARY KEY, b INT, INDEX (b))", 2, 1}, // 'b' index + {"(a INT PRIMARY KEY, b INT, FAMILY (a), FAMILY (b), INDEX (b))", 1, 2}, // Primary index + {"(a INT PRIMARY KEY, b INT, FAMILY (a), FAMILY (b), INDEX (b))", 2, 1}, // 'b' index } for i, test := range tests { diff --git a/pkg/sql/sqlbase/table.go b/pkg/sql/sqlbase/table.go index 604cee4a2756..d0d310b5f25c 100644 --- a/pkg/sql/sqlbase/table.go +++ b/pkg/sql/sqlbase/table.go @@ -167,6 +167,12 @@ func PopulateTypeAttrs(base ColumnType, typ coltypes.T) (ColumnType, error) { // MakeColumnDefDescs creates the column descriptor for a column, as well as the // index descriptor if the column is a primary key or unique. // +// If the column type *may* be SERIAL (or SERIAL-like), it is the +// caller's responsibility to call sql.processSerialInColumnDef() and +// sql.doCreateSequence() before MakeColumnDefDescs() to remove the +// SERIAL type and replace it with a suitable integer type and default +// expression. +// // semaCtx and evalCtx can be nil if no default expression is used for the // column. // @@ -192,14 +198,14 @@ func MakeColumnDefDescs( return nil, nil, nil, err } - if t, ok := d.Type.(*coltypes.TInt); ok { - if t.IsSerial() { - if d.HasDefaultExpr() { - return nil, nil, nil, fmt.Errorf("SERIAL column %q cannot have a default value", d.Name) - } - s := "unique_rowid()" - col.DefaultExpr = &s - } + if t, ok := d.Type.(*coltypes.TInt); ok && t.IsSerial() { + // To the reader of this code: if control arrives here, this means + // the caller has not suitably called processSerialInColumnDef() + // prior to calling MakeColumnDefDescs. The dependent sequences + // must be created, and the SERIAL type eliminated, prior to this + // point. + return nil, nil, nil, pgerror.NewError(pgerror.CodeFeatureNotSupportedError, + "SERIAL cannot be used in this context") } if len(d.CheckExprs) > 0 { diff --git a/pkg/sql/vars.go b/pkg/sql/vars.go index 3a93b254f735..35c9356c99e4 100644 --- a/pkg/sql/vars.go +++ b/pkg/sql/vars.go @@ -329,6 +329,35 @@ var varGen = map[string]sessionVar{ }, }, + // CockroachDB extension. + `experimental_serial_normalization`: { + Set: func( + _ context.Context, m *sessionDataMutator, + evalCtx *extendedEvalContext, values []tree.TypedExpr, + ) error { + s, err := getStringVal(&evalCtx.EvalContext, `experimental_serial_normalization`, values) + if err != nil { + return err + } + mode, ok := sessiondata.SerialNormalizationModeFromString(s) + if !ok { + return newVarValueError(`experimental_serial_normalization`, s, + "rowid", "virtual_sequence", "sql_sequence") + } + m.SetSerialNormalizationMode(mode) + + return nil + }, + Get: func(evalCtx *extendedEvalContext) string { + return evalCtx.SessionData.SerialNormalizationMode.String() + }, + Reset: func(m *sessionDataMutator) error { + m.SetSerialNormalizationMode(sessiondata.SerialNormalizationMode( + SerialNormalizationMode.Get(&m.settings.SV))) + return nil + }, + }, + // See https://www.postgresql.org/docs/10/static/runtime-config-client.html `extra_float_digits`: { Set: func( diff --git a/pkg/sql/virtual_schema.go b/pkg/sql/virtual_schema.go index 9ba36f7b4665..22db56f24947 100644 --- a/pkg/sql/virtual_schema.go +++ b/pkg/sql/virtual_schema.go @@ -231,6 +231,8 @@ func initVirtualTableDesc( } } + // Virtual tables never use SERIAL so we need not process SERIAL + // types here. return MakeTableDesc( ctx, nil, /* txn */