From 249b87e52bdaed9535ff79403e2c174687175f57 Mon Sep 17 00:00:00 2001 From: Oliver Tan Date: Mon, 9 Aug 2021 08:53:41 +1000 Subject: [PATCH 1/3] sessiondatapb: move SequenceCache to LocalOnlySessionData This actually affects the results of my session migration test, so I think we actually need to include it. Release note: None --- pkg/sql/exec_util.go | 2 +- pkg/sql/planner.go | 2 +- pkg/sql/sessiondata/BUILD.bazel | 1 - pkg/sql/sessiondata/session_data.go | 4 - pkg/sql/sessiondatapb/BUILD.bazel | 1 + .../local_only_session_data.pb.go | 600 +++++++++++++++--- .../local_only_session_data.proto | 19 + .../sequence_cache.go | 37 +- 8 files changed, 538 insertions(+), 128 deletions(-) rename pkg/sql/{sessiondata => sessiondatapb}/sequence_cache.go (60%) diff --git a/pkg/sql/exec_util.go b/pkg/sql/exec_util.go index e45b043285de..7c69de8e820b 100644 --- a/pkg/sql/exec_util.go +++ b/pkg/sql/exec_util.go @@ -2617,7 +2617,7 @@ func (m *sessionDataMutator) SetNoticeDisplaySeverity(severity pgnotice.DisplayS // initSequenceCache creates an empty sequence cache instance for the session. func (m *sessionDataMutator) initSequenceCache() { - m.data.SequenceCache = sessiondata.SequenceCache{} + m.data.SequenceCache = sessiondatapb.SequenceCache{} } // SetIntervalStyle sets the IntervalStyle for the given session. diff --git a/pkg/sql/planner.go b/pkg/sql/planner.go index 44f45d4ffc6a..dcb46af811c4 100644 --- a/pkg/sql/planner.go +++ b/pkg/sql/planner.go @@ -506,7 +506,7 @@ func (p *planner) ExecCfg() *ExecutorConfig { // GetOrInitSequenceCache returns the sequence cache for the session. // If the sequence cache has not been used yet, it initializes the cache // inside the session data. -func (p *planner) GetOrInitSequenceCache() sessiondata.SequenceCache { +func (p *planner) GetOrInitSequenceCache() sessiondatapb.SequenceCache { if p.SessionData().SequenceCache == nil { p.sessionDataMutator.initSequenceCache() } diff --git a/pkg/sql/sessiondata/BUILD.bazel b/pkg/sql/sessiondata/BUILD.bazel index 827762bdff54..88a9e13a6ba1 100644 --- a/pkg/sql/sessiondata/BUILD.bazel +++ b/pkg/sql/sessiondata/BUILD.bazel @@ -5,7 +5,6 @@ go_library( srcs = [ "internal.go", "search_path.go", - "sequence_cache.go", "sequence_state.go", "session_data.go", ], diff --git a/pkg/sql/sessiondata/session_data.go b/pkg/sql/sessiondata/session_data.go index 7be2a0a60d30..5eefb1da406d 100644 --- a/pkg/sql/sessiondata/session_data.go +++ b/pkg/sql/sessiondata/session_data.go @@ -137,10 +137,6 @@ type LocalUnmigratableSessionData struct { // descpb.ID -> descpb.ID, but cannot be stored as such due to package // dependencies. Temporary tables are not supported in session migrations. DatabaseIDToTempSchemaID map[uint32]uint32 - // SequenceCache stores sequence values which have been cached using the - // CACHE sequence option. - // Cached sequence options are not yet supported during session migrations. - SequenceCache SequenceCache /////////////////////////////////////////////////////////////////////////// // WARNING: consider whether a session parameter you're adding needs to // diff --git a/pkg/sql/sessiondatapb/BUILD.bazel b/pkg/sql/sessiondatapb/BUILD.bazel index 48e44d285bd4..84bf5fc888ab 100644 --- a/pkg/sql/sessiondatapb/BUILD.bazel +++ b/pkg/sql/sessiondatapb/BUILD.bazel @@ -6,6 +6,7 @@ go_library( name = "sessiondatapb", srcs = [ "local_only_session_data.go", + "sequence_cache.go", "session_data.go", ], embed = [":sessiondatapb_go_proto"], diff --git a/pkg/sql/sessiondatapb/local_only_session_data.pb.go b/pkg/sql/sessiondatapb/local_only_session_data.pb.go index 66a71c85891d..b98df8cd626f 100644 --- a/pkg/sql/sessiondatapb/local_only_session_data.pb.go +++ b/pkg/sql/sessiondatapb/local_only_session_data.pb.go @@ -7,6 +7,7 @@ import ( fmt "fmt" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys" io "io" math "math" math_bits "math/bits" @@ -169,6 +170,9 @@ type LocalOnlySessionData struct { SerialNormalizationMode SerialNormalizationMode `protobuf:"varint,42,opt,name=serial_normalization_mode,json=serialNormalizationMode,proto3,casttype=SerialNormalizationMode" json:"serial_normalization_mode,omitempty"` // NewSchemaChangerMode indicates whether to use the new schema changer. NewSchemaChangerMode NewSchemaChangerMode `protobuf:"varint,43,opt,name=new_schema_changer_mode,json=newSchemaChangerMode,proto3,casttype=NewSchemaChangerMode" json:"new_schema_changer_mode,omitempty"` + // SequenceCache stores sequence values which have been cached using the + // CACHE sequence option. + SequenceCache SequenceCache `protobuf:"bytes,44,rep,name=sequence_cache,json=sequenceCache,proto3,casttype=SequenceCache" json:"sequence_cache,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (m *LocalOnlySessionData) Reset() { *m = LocalOnlySessionData{} } @@ -200,8 +204,55 @@ func (m *LocalOnlySessionData) XXX_DiscardUnknown() { var xxx_messageInfo_LocalOnlySessionData proto.InternalMessageInfo +// SequenceCacheEntry is an entry in a SequenceCache. +type SequenceCacheEntry struct { + // CachedVersion stores the descpb.DescriptorVersion that cached values are associated with. + // The version is checked to determine if cache needs to be invalidated. The version is stored as + // a uint32 to prevent an import cycle with the descpb package. + CachedVersion uint32 `protobuf:"varint,1,opt,name=cached_version,json=cachedVersion,proto3" json:"cached_version,omitempty"` + // CurrentValue stores the present value of the sequence to be given out. + CurrentValue int64 `protobuf:"varint,2,opt,name=current_value,json=currentValue,proto3" json:"current_value,omitempty"` + // Increment stores the amount to Increment the currentVal by each time the + // currentVal is used. This value corresponds to descpb.TableDescriptor_SequenceOpts.Increment. + Increment int64 `protobuf:"varint,3,opt,name=increment,proto3" json:"increment,omitempty"` + // NumValues represents the number of values to cache. The cache is considered + // to be empty when NumValues is 0. + NumValues int64 `protobuf:"varint,4,opt,name=num_values,json=numValues,proto3" json:"num_values,omitempty"` +} + +func (m *SequenceCacheEntry) Reset() { *m = SequenceCacheEntry{} } +func (m *SequenceCacheEntry) String() string { return proto.CompactTextString(m) } +func (*SequenceCacheEntry) ProtoMessage() {} +func (*SequenceCacheEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_21ead158cf36da28, []int{1} +} +func (m *SequenceCacheEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SequenceCacheEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *SequenceCacheEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_SequenceCacheEntry.Merge(m, src) +} +func (m *SequenceCacheEntry) XXX_Size() int { + return m.Size() +} +func (m *SequenceCacheEntry) XXX_DiscardUnknown() { + xxx_messageInfo_SequenceCacheEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_SequenceCacheEntry proto.InternalMessageInfo + func init() { proto.RegisterType((*LocalOnlySessionData)(nil), "cockroach.sql.sessiondatapb.LocalOnlySessionData") + proto.RegisterMapType((SequenceCache)(nil), "cockroach.sql.sessiondatapb.LocalOnlySessionData.SequenceCacheEntry") + proto.RegisterType((*SequenceCacheEntry)(nil), "cockroach.sql.sessiondatapb.SequenceCacheEntry") } func init() { @@ -209,101 +260,111 @@ func init() { } var fileDescriptor_21ead158cf36da28 = []byte{ - // 1495 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x96, 0x5f, 0x53, 0x1b, 0xbb, - 0x19, 0xc6, 0x71, 0xcf, 0xe9, 0x69, 0x8e, 0x08, 0x09, 0x6c, 0x4c, 0xbc, 0x40, 0xb0, 0x81, 0x90, - 0x84, 0x34, 0x2d, 0xb4, 0xd3, 0x3f, 0x93, 0xb6, 0xd3, 0x69, 0x83, 0xc1, 0xcd, 0x1f, 0x12, 0x1c, - 0x1b, 0xca, 0x34, 0xed, 0x8c, 0x46, 0xec, 0xbe, 0xb6, 0x55, 0xb4, 0xd2, 0x5a, 0xd2, 0x02, 0xe6, - 0x43, 0x74, 0x3a, 0xd3, 0x2f, 0x95, 0xcb, 0x5c, 0xe6, 0x8a, 0x69, 0x9d, 0x6f, 0xc1, 0x55, 0x47, - 0xaf, 0x76, 0x8d, 0x9d, 0x26, 0xd3, 0x3b, 0xd0, 0xf3, 0x7b, 0x1e, 0x4b, 0xaf, 0x5e, 0x49, 0x4b, - 0xb6, 0x4c, 0x5f, 0x6c, 0x19, 0x30, 0x86, 0x2b, 0x19, 0x33, 0xcb, 0xd2, 0xe3, 0x2d, 0xa1, 0x22, - 0x26, 0xa8, 0x92, 0x62, 0x40, 0x73, 0x81, 0x3a, 0x65, 0x33, 0xd5, 0xca, 0xaa, 0x60, 0x29, 0x52, - 0xd1, 0x89, 0x56, 0x2c, 0xea, 0x6d, 0x9a, 0xbe, 0xd8, 0x9c, 0xb0, 0x2e, 0x96, 0xbb, 0xaa, 0xab, - 0x90, 0xdb, 0x72, 0x7f, 0x79, 0xcb, 0xda, 0x3f, 0xee, 0x92, 0xf2, 0x9e, 0x0b, 0xdd, 0x97, 0x62, - 0xd0, 0xf6, 0x86, 0x1d, 0x66, 0x59, 0xf0, 0x13, 0x12, 0x18, 0x76, 0x0a, 0xd4, 0xb2, 0x63, 0x01, - 0x86, 0xa6, 0x1a, 0x3a, 0xfc, 0x3c, 0x2c, 0xad, 0x94, 0x36, 0xbe, 0x6f, 0xcd, 0x3a, 0xe5, 0x00, - 0x85, 0x26, 0x8e, 0x07, 0x7f, 0x25, 0x4b, 0x2a, 0xb5, 0x3c, 0xe1, 0x17, 0xa0, 0x69, 0xe7, 0x84, - 0x46, 0xcc, 0x44, 0x2c, 0x06, 0x43, 0x05, 0x4f, 0xb8, 0x0d, 0x7f, 0xb0, 0x52, 0xda, 0xf8, 0x66, - 0xfb, 0xde, 0xf0, 0xb2, 0x16, 0xee, 0x17, 0x58, 0xe3, 0x55, 0x3d, 0x87, 0xf6, 0x1c, 0xd3, 0x0a, - 0x47, 0x01, 0x8d, 0x93, 0x09, 0x25, 0xf8, 0x25, 0xb9, 0x69, 0x6c, 0x62, 0xa9, 0xe5, 0x09, 0xa8, - 0xcc, 0x86, 0xdf, 0x60, 0xda, 0xdc, 0xd5, 0x65, 0x6d, 0xc6, 0x0d, 0x6d, 0xee, 0x64, 0x9a, 0x59, - 0xae, 0x64, 0x6b, 0xda, 0x61, 0x07, 0x9e, 0x0a, 0x9e, 0x93, 0x0a, 0x8f, 0x05, 0x50, 0x2e, 0x47, - 0xa5, 0x2a, 0x02, 0xbe, 0xfd, 0x5a, 0x40, 0xd9, 0x39, 0x5e, 0xc8, 0xbc, 0x0e, 0x45, 0x12, 0x25, - 0xf7, 0x8b, 0x24, 0xab, 0x99, 0x34, 0x2c, 0x72, 0xf0, 0xff, 0xa4, 0xfe, 0xf0, 0x6b, 0xa9, 0x35, - 0x9f, 0x7a, 0x70, 0xed, 0xfd, 0xec, 0x07, 0x7e, 0x4d, 0x2a, 0x52, 0x59, 0x1e, 0x01, 0x8d, 0xb9, - 0x49, 0x05, 0x73, 0x9b, 0x7b, 0x0a, 0x9a, 0xdb, 0x41, 0xf8, 0xdd, 0x4a, 0x69, 0x63, 0xa6, 0x35, - 0xef, 0xe5, 0x1d, 0xaf, 0xb6, 0x73, 0x31, 0xd8, 0x24, 0x77, 0x34, 0x28, 0x1d, 0x83, 0xa6, 0x7f, - 0x57, 0x5c, 0x16, 0xd5, 0xfe, 0x91, 0x9b, 0x48, 0x6b, 0x2e, 0x97, 0x5e, 0x3a, 0xc5, 0x17, 0xf2, - 0x67, 0xa4, 0x1c, 0x43, 0x87, 0x65, 0xc2, 0x52, 0x7b, 0x2e, 0x69, 0xaa, 0xb9, 0xc2, 0x1f, 0xb9, - 0x81, 0x86, 0x20, 0xd7, 0x0e, 0xce, 0x65, 0x33, 0x57, 0x82, 0x9f, 0x93, 0xf9, 0x71, 0x87, 0x06, - 0x16, 0x63, 0xf7, 0x85, 0xdf, 0xaf, 0x94, 0x36, 0x6e, 0x8c, 0x5b, 0x5a, 0xc0, 0x62, 0xd7, 0x43, - 0xc1, 0x36, 0xa9, 0x8e, 0x5b, 0x32, 0x03, 0xb4, 0xa3, 0x84, 0x50, 0x67, 0xa0, 0xd1, 0x6f, 0x42, - 0x82, 0xde, 0xc5, 0x6b, 0xef, 0xa1, 0x81, 0x46, 0x8e, 0xb8, 0x18, 0x13, 0xec, 0x93, 0xf5, 0x94, - 0x69, 0xcb, 0x99, 0x10, 0x03, 0x57, 0x13, 0xab, 0xf9, 0x71, 0x66, 0x21, 0xa6, 0xa9, 0x60, 0xd2, - 0xb8, 0x11, 0xd7, 0x7c, 0x71, 0x38, 0x8d, 0x49, 0xab, 0x23, 0x76, 0xe7, 0x1a, 0x6d, 0x3a, 0x72, - 0x27, 0x07, 0x83, 0xa7, 0xe4, 0xba, 0xbd, 0x70, 0x4a, 0x3d, 0x6e, 0xac, 0xea, 0x6a, 0x96, 0x98, - 0xf0, 0x26, 0x86, 0xdc, 0x1d, 0xe9, 0x87, 0x06, 0x9e, 0x8f, 0xd4, 0xe0, 0x8f, 0x64, 0x79, 0xd2, - 0x99, 0x64, 0xc2, 0x72, 0x1a, 0x29, 0x41, 0x8d, 0x65, 0xd6, 0x84, 0x33, 0x68, 0x5f, 0x18, 0xb7, - 0xbf, 0x76, 0x48, 0x5d, 0x89, 0xb6, 0x03, 0x82, 0xdf, 0x92, 0x05, 0x3c, 0xb6, 0xdc, 0x0e, 0x68, - 0x41, 0xc5, 0xd4, 0x00, 0xd3, 0x51, 0x2f, 0xbc, 0x85, 0xee, 0x4a, 0x01, 0x14, 0xa7, 0x23, 0x6e, - 0xa3, 0x1c, 0xac, 0x92, 0x9b, 0x86, 0x75, 0x80, 0x66, 0x69, 0xcc, 0x2c, 0x98, 0xf0, 0x36, 0xe2, - 0xd3, 0x6e, 0xec, 0xd0, 0x0f, 0x05, 0x7f, 0x21, 0x4b, 0xee, 0x70, 0x82, 0xa6, 0x42, 0xa9, 0x93, - 0x2c, 0xcd, 0x5b, 0xa1, 0xa3, 0xdc, 0x41, 0x34, 0xe1, 0xac, 0x73, 0x6c, 0x2f, 0x0d, 0x2f, 0x6b, - 0x95, 0x26, 0x62, 0x7b, 0x48, 0x61, 0x57, 0x34, 0x94, 0x6e, 0xbc, 0x32, 0xad, 0x4a, 0xfa, 0x25, - 0xe1, 0xc4, 0xb8, 0xfe, 0xba, 0xe0, 0xdd, 0x0b, 0xd6, 0xc5, 0x4c, 0x0a, 0xd2, 0x57, 0x7d, 0x0e, - 0x27, 0x31, 0xe7, 0x25, 0xc7, 0xef, 0x7a, 0x21, 0x78, 0x46, 0x96, 0x35, 0xf4, 0x33, 0xae, 0x81, - 0xc2, 0x79, 0x2a, 0x78, 0xc4, 0xad, 0x6b, 0xb2, 0x84, 0xe9, 0x01, 0x3d, 0x81, 0x81, 0x09, 0x03, - 0xbf, 0xf3, 0x39, 0xb4, 0x9b, 0x33, 0x4d, 0x8f, 0xbc, 0x82, 0x81, 0x71, 0x47, 0xa1, 0xa3, 0x74, - 0x04, 0xd4, 0x5d, 0x31, 0xa9, 0xe2, 0xd2, 0x52, 0x0d, 0xc6, 0x32, 0x6d, 0xc3, 0x3b, 0x68, 0x9e, - 0x47, 0xb9, 0x5d, 0xa8, 0x2d, 0x2f, 0x06, 0x4f, 0xc9, 0x02, 0x73, 0x1d, 0xe4, 0x2e, 0xaa, 0x94, - 0x69, 0xa0, 0xcc, 0xb8, 0x62, 0x63, 0xc3, 0x84, 0x65, 0xef, 0x44, 0xa0, 0xe9, 0xf5, 0x67, 0x66, - 0x3f, 0xb5, 0xae, 0x47, 0xdc, 0x22, 0x2d, 0x24, 0x69, 0x71, 0xd1, 0x15, 0x8b, 0x9c, 0xf7, 0x8b, - 0x74, 0x92, 0xbf, 0xe9, 0x8a, 0x45, 0xee, 0x93, 0x75, 0x9e, 0xe4, 0x8b, 0x8b, 0x94, 0xc8, 0x12, - 0x49, 0xb1, 0xff, 0xdc, 0xb9, 0xe6, 0xb2, 0x3b, 0x0a, 0xb8, 0xeb, 0x7b, 0xb3, 0x60, 0xeb, 0x88, - 0x36, 0xc7, 0xc8, 0x22, 0xf0, 0x57, 0xa4, 0x12, 0x6b, 0x95, 0x52, 0x90, 0x59, 0x42, 0x4f, 0x99, - 0xc8, 0x60, 0x94, 0x51, 0xc1, 0x8c, 0xb2, 0x93, 0x77, 0x65, 0x96, 0xfc, 0xd9, 0x89, 0x85, 0xed, - 0x88, 0x3c, 0x56, 0xa7, 0xa0, 0x35, 0x8f, 0x8b, 0x9e, 0xd4, 0xd0, 0x75, 0xf7, 0xd1, 0x85, 0x92, - 0x40, 0x23, 0x25, 0x3b, 0xfc, 0x7a, 0x32, 0x21, 0x06, 0xad, 0x17, 0x06, 0x6c, 0xd0, 0x16, 0xe2, - 0xef, 0x94, 0x84, 0x3a, 0xc2, 0x45, 0xf0, 0x1f, 0xc8, 0xbd, 0x1e, 0x33, 0x3d, 0x6a, 0x7a, 0x4c, - 0xc7, 0x10, 0x53, 0x2e, 0x63, 0x38, 0x1f, 0xab, 0xcc, 0x82, 0x6f, 0x78, 0xc7, 0xb4, 0x3d, 0xf2, - 0xc2, 0x13, 0x45, 0xc0, 0x6f, 0xc8, 0x82, 0x3b, 0xa1, 0xb8, 0x1d, 0x9d, 0x4c, 0x08, 0x5f, 0x5a, - 0x6a, 0x22, 0x26, 0x4d, 0xb8, 0xe8, 0x4f, 0x5b, 0x01, 0x34, 0x32, 0x21, 0xb0, 0xbe, 0x6d, 0xa7, - 0x06, 0xbf, 0x23, 0x8b, 0xa3, 0xe2, 0x1a, 0x10, 0x10, 0x59, 0x6c, 0x64, 0xdf, 0xfe, 0xe1, 0x92, - 0x3f, 0x2c, 0x05, 0xd1, 0x46, 0xa0, 0xa1, 0xb4, 0x3f, 0x0a, 0xc1, 0x06, 0x99, 0xe5, 0xd2, 0x80, - 0xb6, 0xb4, 0xc3, 0x8c, 0xa5, 0x29, 0xb3, 0xbd, 0xf0, 0x1e, 0x5a, 0x6e, 0xf9, 0xf1, 0x06, 0x33, - 0xb6, 0xc9, 0x6c, 0x2f, 0x78, 0x4e, 0x56, 0x99, 0xb0, 0xa0, 0x8b, 0x0d, 0xb4, 0x83, 0x14, 0x68, - 0x17, 0x24, 0x68, 0x26, 0x46, 0xeb, 0x5c, 0x46, 0xeb, 0x32, 0x82, 0x7e, 0xf7, 0x0e, 0x06, 0x29, - 0xfc, 0xc9, 0x53, 0xc5, 0x5a, 0x7f, 0x4a, 0x02, 0x33, 0x90, 0x51, 0x4f, 0x2b, 0xa9, 0x32, 0x43, - 0x23, 0x95, 0xb8, 0x1b, 0xb8, 0xea, 0x9b, 0x67, 0x4c, 0xa9, 0xa3, 0x10, 0x3c, 0x24, 0xb7, 0x7d, - 0x3c, 0x35, 0xd0, 0xc7, 0x8a, 0x84, 0x35, 0x64, 0x67, 0xfc, 0x70, 0x1b, 0xfa, 0xae, 0x10, 0xc1, - 0x01, 0x79, 0x94, 0x73, 0x99, 0xe4, 0xfd, 0x0c, 0xe8, 0x19, 0xb7, 0x3d, 0x95, 0x59, 0xbf, 0x19, - 0x6e, 0x77, 0x8d, 0xd5, 0x8c, 0x4b, 0x6b, 0xc2, 0x55, 0xf4, 0xdf, 0xf7, 0xf8, 0x21, 0xd2, 0x47, - 0x1e, 0xc6, 0x6d, 0xa9, 0x5f, 0xa3, 0xc1, 0xef, 0xc9, 0x92, 0xb1, 0xd9, 0x31, 0x8d, 0x98, 0x65, - 0x42, 0x75, 0x3f, 0x6f, 0xf9, 0x35, 0x4c, 0x0a, 0x1d, 0x52, 0xf7, 0xc4, 0x64, 0xe7, 0xbf, 0x25, - 0x0f, 0xe0, 0x3c, 0x05, 0xcd, 0x13, 0x90, 0x96, 0x09, 0xb7, 0xd8, 0x14, 0x6f, 0xe5, 0xbc, 0x8a, - 0x1a, 0xce, 0x34, 0x77, 0xb7, 0xd4, 0x7d, 0xfc, 0x4a, 0x58, 0x1b, 0x87, 0xeb, 0x39, 0xeb, 0x0b, - 0xd9, 0xca, 0xc9, 0xe0, 0x6f, 0xe4, 0x49, 0xa4, 0xd2, 0xc1, 0xe4, 0x09, 0x3a, 0xeb, 0x81, 0xa4, - 0x31, 0x70, 0x69, 0x41, 0x0b, 0x60, 0xa7, 0x6e, 0x0c, 0xa7, 0x1a, 0xae, 0xe3, 0x0c, 0x1f, 0x39, - 0xcb, 0xf8, 0x49, 0x3a, 0xea, 0x81, 0xdc, 0x99, 0xe0, 0x71, 0xe2, 0xee, 0xe6, 0x2d, 0xaa, 0x6d, - 0x35, 0xb0, 0x84, 0x6a, 0x70, 0x9d, 0x83, 0xaf, 0x72, 0xf8, 0xc0, 0x37, 0x53, 0x5e, 0x77, 0xd4, - 0x5b, 0xd7, 0xb2, 0x7f, 0x5b, 0x4d, 0x26, 0xac, 0xa1, 0xc7, 0x59, 0xc7, 0x5d, 0xaf, 0x86, 0x5f, - 0x40, 0xf8, 0xb0, 0x78, 0x5b, 0x51, 0xda, 0x46, 0xa5, 0xcd, 0x2f, 0xc0, 0xbd, 0x30, 0xa9, 0x56, - 0x29, 0xeb, 0x32, 0xeb, 0xbe, 0x14, 0xd2, 0xcc, 0x52, 0x7c, 0x7e, 0xb9, 0xec, 0x86, 0x8f, 0x7c, - 0xcf, 0x8f, 0xf4, 0x17, 0x4e, 0xde, 0xcf, 0xd5, 0xe0, 0x5f, 0x25, 0x32, 0x51, 0x2a, 0x7c, 0xf0, - 0x4c, 0x5f, 0xe0, 0xdd, 0x85, 0x05, 0x49, 0x54, 0x0c, 0xe1, 0x06, 0x7e, 0x5e, 0x34, 0x86, 0x97, - 0xb5, 0xda, 0xee, 0x18, 0xed, 0x9e, 0xbc, 0xf6, 0xdb, 0xbd, 0x66, 0xce, 0xbe, 0x56, 0x31, 0x5c, - 0xfd, 0x7f, 0xa4, 0x55, 0x83, 0xcf, 0x00, 0xd3, 0x17, 0xe3, 0x40, 0xd0, 0x20, 0x33, 0x6e, 0x1e, - 0xd4, 0x4d, 0x04, 0x7f, 0xff, 0x31, 0xfe, 0xfe, 0xda, 0xf0, 0xb2, 0x36, 0x9d, 0x07, 0xe6, 0xbf, - 0x75, 0x3b, 0xff, 0x77, 0xf7, 0x1c, 0x22, 0xcc, 0x9e, 0x76, 0xc6, 0x76, 0x5f, 0x60, 0xce, 0x11, - 0x59, 0x30, 0xa0, 0x39, 0x13, 0x54, 0x2a, 0x9d, 0x30, 0xc1, 0x2f, 0xb0, 0xbe, 0x3e, 0xf3, 0xc7, - 0x98, 0xb9, 0x74, 0x75, 0x59, 0xab, 0xb4, 0x11, 0x7a, 0x33, 0xce, 0x60, 0x58, 0xc5, 0x7c, 0x59, - 0x08, 0xf6, 0x49, 0x45, 0xc2, 0x19, 0x35, 0x51, 0x0f, 0x12, 0x46, 0xa3, 0x1e, 0x93, 0x5d, 0xd0, - 0x3e, 0xf6, 0x09, 0xc6, 0x86, 0x57, 0x97, 0xb5, 0xf2, 0x1b, 0x38, 0x6b, 0x23, 0x51, 0xf7, 0x00, - 0x66, 0x96, 0xe5, 0x17, 0x46, 0x5f, 0x7e, 0x7b, 0x63, 0x65, 0x76, 0x75, 0x7b, 0xeb, 0xfd, 0x7f, - 0xaa, 0x53, 0xef, 0x87, 0xd5, 0xd2, 0x87, 0x61, 0xb5, 0xf4, 0x71, 0x58, 0x2d, 0xfd, 0x7b, 0x58, - 0x2d, 0xfd, 0xf3, 0x53, 0x75, 0xea, 0xc3, 0xa7, 0xea, 0xd4, 0xc7, 0x4f, 0xd5, 0xa9, 0x77, 0x33, - 0x13, 0xdf, 0xd5, 0xc7, 0xdf, 0xe1, 0x87, 0xf4, 0x2f, 0xfe, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xe4, - 0xaf, 0xd6, 0x25, 0xae, 0x0b, 0x00, 0x00, + // 1661 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x97, 0xdd, 0x72, 0x1b, 0xb7, + 0x15, 0xc7, 0xcd, 0x38, 0x49, 0x6d, 0xc8, 0xb4, 0x65, 0x44, 0x0e, 0x57, 0x92, 0x45, 0x4a, 0xb2, + 0x1d, 0x2b, 0x4d, 0x2a, 0xb5, 0xe9, 0xc7, 0xb8, 0xe9, 0x74, 0xda, 0x88, 0x12, 0x6b, 0xc7, 0x4e, + 0xa4, 0x2c, 0xe5, 0x78, 0x9a, 0x76, 0x06, 0x03, 0xed, 0x1e, 0x92, 0xa8, 0xb0, 0xc0, 0x12, 0xc0, + 0x4a, 0xa2, 0x2e, 0x3a, 0xd3, 0x37, 0xe8, 0x4c, 0xaf, 0xfb, 0x3e, 0xb9, 0xcc, 0x65, 0xae, 0x34, + 0xad, 0xfc, 0x16, 0xbe, 0xea, 0xe0, 0x60, 0x97, 0x1f, 0xb6, 0x92, 0xde, 0x89, 0xe7, 0xff, 0x3b, + 0xff, 0x05, 0x0e, 0x0e, 0x3e, 0x44, 0xb6, 0xec, 0x50, 0x6e, 0x59, 0xb0, 0x56, 0x68, 0x95, 0x72, + 0xc7, 0xf3, 0xc3, 0x2d, 0xa9, 0x13, 0x2e, 0x99, 0x56, 0x72, 0xc4, 0x4a, 0x81, 0x79, 0x65, 0x33, + 0x37, 0xda, 0x69, 0xba, 0x9c, 0xe8, 0xe4, 0xc8, 0x68, 0x9e, 0x0c, 0x36, 0xed, 0x50, 0x6e, 0xce, + 0xa4, 0x2e, 0x2d, 0xf4, 0x75, 0x5f, 0x23, 0xb7, 0xe5, 0xff, 0x0a, 0x29, 0xeb, 0xff, 0x88, 0xc8, + 0xc2, 0x33, 0x6f, 0xba, 0xa7, 0xe4, 0xa8, 0x1b, 0x12, 0x76, 0xb8, 0xe3, 0xf4, 0x63, 0x42, 0x2d, + 0x3f, 0x06, 0xe6, 0xf8, 0xa1, 0x04, 0xcb, 0x72, 0x03, 0x3d, 0x71, 0x1a, 0xd5, 0x56, 0x6b, 0x1b, + 0xd7, 0xe3, 0x79, 0xaf, 0x1c, 0xa0, 0xb0, 0x8f, 0x71, 0xfa, 0x17, 0xb2, 0xac, 0x73, 0x27, 0x32, + 0x71, 0x06, 0x86, 0xf5, 0x8e, 0x58, 0xc2, 0x6d, 0xc2, 0x53, 0xb0, 0x4c, 0x8a, 0x4c, 0xb8, 0xe8, + 0xad, 0xd5, 0xda, 0xc6, 0xd5, 0xed, 0xbb, 0x17, 0xe7, 0xad, 0x68, 0xaf, 0xc2, 0x3a, 0x4f, 0xdb, + 0x25, 0xf4, 0xcc, 0x33, 0x71, 0x34, 0x36, 0xe8, 0x1c, 0xcd, 0x28, 0xf4, 0x57, 0xe4, 0x86, 0x75, + 0x99, 0x63, 0x4e, 0x64, 0xa0, 0x0b, 0x17, 0x5d, 0x45, 0xb7, 0xdb, 0xaf, 0xce, 0x5b, 0x75, 0x1f, + 0xda, 0xdc, 0x29, 0x0c, 0x77, 0x42, 0xab, 0x78, 0xce, 0x63, 0x07, 0x81, 0xa2, 0x8f, 0x49, 0x43, + 0xa4, 0x12, 0x98, 0x50, 0xe3, 0x52, 0x55, 0x06, 0x6f, 0xff, 0x90, 0xc1, 0x82, 0xcf, 0x78, 0xa2, + 0xca, 0x3a, 0x54, 0x4e, 0x8c, 0xdc, 0xab, 0x9c, 0x9c, 0xe1, 0xca, 0xf2, 0xc4, 0xc3, 0x6f, 0xb8, + 0xbe, 0xf3, 0x43, 0xae, 0xad, 0xe0, 0x7a, 0x30, 0xc9, 0x7d, 0xed, 0x03, 0xbf, 0x21, 0x0d, 0xa5, + 0x9d, 0x48, 0x80, 0xa5, 0xc2, 0xe6, 0x92, 0xfb, 0xc5, 0x3d, 0x06, 0x23, 0xdc, 0x28, 0x7a, 0x77, + 0xb5, 0xb6, 0x51, 0x8f, 0xef, 0x04, 0x79, 0x27, 0xa8, 0xdd, 0x52, 0xa4, 0x9b, 0xe4, 0x3d, 0x03, + 0xda, 0xa4, 0x60, 0xd8, 0xdf, 0xb4, 0x50, 0x55, 0xb5, 0x7f, 0xe2, 0x07, 0x12, 0xdf, 0x2e, 0xa5, + 0xcf, 0xbd, 0x12, 0x0a, 0xf9, 0x73, 0xb2, 0x90, 0x42, 0x8f, 0x17, 0xd2, 0x31, 0x77, 0xaa, 0x58, + 0x6e, 0x84, 0xc6, 0x8f, 0x5c, 0xc3, 0x04, 0x5a, 0x6a, 0x07, 0xa7, 0x6a, 0xbf, 0x54, 0xe8, 0x2f, + 0xc8, 0x9d, 0xe9, 0x0c, 0x03, 0x3c, 0xc5, 0xee, 0x8b, 0xae, 0xaf, 0xd6, 0x36, 0xae, 0x4d, 0xa7, + 0xc4, 0xc0, 0x53, 0xdf, 0x43, 0x74, 0x9b, 0x34, 0xa7, 0x53, 0x0a, 0x0b, 0xac, 0xa7, 0xa5, 0xd4, + 0x27, 0x60, 0x30, 0xdf, 0x46, 0x04, 0x73, 0x97, 0x26, 0xb9, 0xcf, 0x2d, 0x74, 0x4a, 0xc4, 0xdb, + 0x58, 0xba, 0x47, 0xee, 0xe7, 0xdc, 0x38, 0xc1, 0xa5, 0x1c, 0xf9, 0x9a, 0x38, 0x23, 0x0e, 0x0b, + 0x07, 0x29, 0xcb, 0x25, 0x57, 0xd6, 0x47, 0x7c, 0xf3, 0xa5, 0xd1, 0x1c, 0x3a, 0xad, 0x8d, 0xd9, + 0x9d, 0x09, 0xba, 0xef, 0xc9, 0x9d, 0x12, 0xa4, 0x8f, 0xc8, 0xa4, 0xbd, 0x70, 0x48, 0x03, 0x61, + 0x9d, 0xee, 0x1b, 0x9e, 0xd9, 0xe8, 0x06, 0x9a, 0xbc, 0x3f, 0xd6, 0x9f, 0x5b, 0x78, 0x3c, 0x56, + 0xe9, 0x1f, 0xc9, 0xca, 0x6c, 0x66, 0x56, 0x48, 0x27, 0x58, 0xa2, 0x25, 0xb3, 0x8e, 0x3b, 0x1b, + 0xd5, 0x31, 0x7d, 0x71, 0x3a, 0xfd, 0x0b, 0x8f, 0xb4, 0xb5, 0xec, 0x7a, 0x80, 0x7e, 0x4a, 0x16, + 0x71, 0xdb, 0x0a, 0x37, 0x62, 0x15, 0x95, 0x32, 0x0b, 0xdc, 0x24, 0x83, 0xe8, 0x26, 0x66, 0x37, + 0x2a, 0xa0, 0xda, 0x1d, 0x69, 0x17, 0x65, 0xba, 0x46, 0x6e, 0x58, 0xde, 0x03, 0x56, 0xe4, 0x29, + 0x77, 0x60, 0xa3, 0x5b, 0x88, 0xcf, 0xf9, 0xd8, 0xf3, 0x10, 0xa2, 0x7f, 0x26, 0xcb, 0x7e, 0x73, + 0x82, 0x61, 0x52, 0xeb, 0xa3, 0x22, 0x2f, 0x5b, 0xa1, 0xa7, 0xfd, 0x46, 0xb4, 0xd1, 0xbc, 0xcf, + 0xd8, 0x5e, 0xbe, 0x38, 0x6f, 0x35, 0xf6, 0x11, 0x7b, 0x86, 0x14, 0x76, 0x45, 0x47, 0x9b, 0xce, + 0x53, 0x1b, 0x37, 0xf2, 0xcb, 0x84, 0x23, 0xeb, 0xfb, 0xeb, 0x4c, 0xf4, 0xcf, 0x78, 0x1f, 0x3d, + 0x19, 0xa8, 0x50, 0xf5, 0xdb, 0x38, 0x88, 0xdb, 0x41, 0xf2, 0xfc, 0x6e, 0x10, 0xe8, 0x67, 0x64, + 0xc5, 0xc0, 0xb0, 0x10, 0x06, 0x18, 0x9c, 0xe6, 0x52, 0x24, 0xc2, 0xf9, 0x26, 0xcb, 0xb8, 0x19, + 0xb1, 0x23, 0x18, 0xd9, 0x88, 0x86, 0x95, 0x2f, 0xa1, 0xdd, 0x92, 0xd9, 0x0f, 0xc8, 0x53, 0x18, + 0x59, 0xbf, 0x15, 0x7a, 0xda, 0x24, 0xc0, 0xfc, 0x11, 0x93, 0x6b, 0xa1, 0x1c, 0x33, 0x60, 0x1d, + 0x37, 0x2e, 0x7a, 0x0f, 0x93, 0xef, 0xa0, 0xdc, 0xad, 0xd4, 0x38, 0x88, 0xf4, 0x11, 0x59, 0xe4, + 0xbe, 0x83, 0xfc, 0x41, 0x95, 0x73, 0x03, 0x8c, 0x5b, 0x5f, 0x6c, 0x6c, 0x98, 0x68, 0x21, 0x64, + 0x22, 0xb0, 0x1f, 0xf4, 0xcf, 0xec, 0x5e, 0xee, 0x7c, 0x8f, 0xf8, 0x49, 0x3a, 0xc8, 0xf2, 0xea, + 0xa0, 0xab, 0x26, 0x79, 0x27, 0x4c, 0xd2, 0x4b, 0xe1, 0xa4, 0xab, 0x26, 0xb9, 0x47, 0xee, 0x8b, + 0xac, 0x9c, 0x5c, 0xa2, 0x65, 0x91, 0x29, 0x86, 0xfd, 0xe7, 0xf7, 0xb5, 0x50, 0xfd, 0xb1, 0xc1, + 0xfb, 0xa1, 0x37, 0x2b, 0xb6, 0x8d, 0xe8, 0xfe, 0x14, 0x59, 0x19, 0xfe, 0x9a, 0x34, 0x52, 0xa3, + 0x73, 0x06, 0xaa, 0xc8, 0xd8, 0x31, 0x97, 0x05, 0x8c, 0x3d, 0x1a, 0xe8, 0xb1, 0xe0, 0xe5, 0x5d, + 0x55, 0x64, 0x5f, 0x7b, 0xb1, 0x4a, 0x7b, 0x41, 0x3e, 0xd4, 0xc7, 0x60, 0x8c, 0x48, 0xab, 0x9e, + 0x34, 0xd0, 0xf7, 0xe7, 0xd1, 0x99, 0x56, 0xc0, 0x12, 0xad, 0x7a, 0x62, 0x32, 0x98, 0x08, 0x8d, + 0xee, 0x57, 0x09, 0xd8, 0xa0, 0x31, 0xe2, 0xdf, 0x68, 0x05, 0x6d, 0x84, 0x2b, 0xe3, 0x3f, 0x90, + 0xbb, 0x03, 0x6e, 0x07, 0xcc, 0x0e, 0xb8, 0x49, 0x21, 0x65, 0x42, 0xa5, 0x70, 0x3a, 0x55, 0x99, + 0xc5, 0xd0, 0xf0, 0x9e, 0xe9, 0x06, 0xe4, 0x49, 0x20, 0x2a, 0x83, 0xdf, 0x92, 0x45, 0xbf, 0x43, + 0x71, 0x39, 0x7a, 0x85, 0x94, 0xa1, 0xb4, 0xcc, 0x26, 0x5c, 0xd9, 0x68, 0x29, 0xec, 0xb6, 0x0a, + 0xe8, 0x14, 0x52, 0x62, 0x7d, 0xbb, 0x5e, 0xa5, 0xbf, 0x23, 0x4b, 0xe3, 0xe2, 0x5a, 0x90, 0x90, + 0x38, 0x6c, 0xe4, 0xd0, 0xfe, 0xd1, 0x72, 0xd8, 0x2c, 0x15, 0xd1, 0x45, 0xa0, 0xa3, 0x4d, 0xd8, + 0x0a, 0x74, 0x83, 0xcc, 0x0b, 0x65, 0xc1, 0x38, 0xd6, 0xe3, 0xd6, 0xb1, 0x9c, 0xbb, 0x41, 0x74, + 0x17, 0x53, 0x6e, 0x86, 0x78, 0x87, 0x5b, 0xb7, 0xcf, 0xdd, 0x80, 0x3e, 0x26, 0x6b, 0x5c, 0x3a, + 0x30, 0xd5, 0x02, 0xba, 0x51, 0x0e, 0xac, 0x0f, 0x0a, 0x0c, 0x97, 0xe3, 0x79, 0xae, 0x60, 0xea, + 0x0a, 0x82, 0x61, 0xf5, 0x0e, 0x46, 0x39, 0xfc, 0x29, 0x50, 0xd5, 0x5c, 0x7f, 0x46, 0xa8, 0x1d, + 0xa9, 0x64, 0x60, 0xb4, 0xd2, 0x85, 0x65, 0x89, 0xce, 0xfc, 0x09, 0xdc, 0x0c, 0xcd, 0x33, 0xa5, + 0xb4, 0x51, 0xa0, 0x1f, 0x90, 0x5b, 0xc1, 0x9e, 0x59, 0x18, 0x62, 0x45, 0xa2, 0x16, 0xb2, 0xf5, + 0x10, 0xee, 0xc2, 0xd0, 0x17, 0x82, 0x1e, 0x90, 0x87, 0x25, 0x57, 0x28, 0x31, 0x2c, 0x80, 0x9d, + 0x08, 0x37, 0xd0, 0x85, 0x0b, 0x8b, 0xe1, 0x57, 0xd7, 0x3a, 0xc3, 0x85, 0x72, 0x36, 0x5a, 0xc3, + 0xfc, 0x7b, 0x01, 0x7f, 0x8e, 0xf4, 0x8b, 0x00, 0xe3, 0xb2, 0xb4, 0x27, 0x28, 0xfd, 0x3d, 0x59, + 0xb6, 0xae, 0x38, 0x64, 0x09, 0x77, 0x5c, 0xea, 0xfe, 0xeb, 0x2d, 0xbf, 0x8e, 0x4e, 0x91, 0x47, + 0xda, 0x81, 0x98, 0xed, 0xfc, 0xaf, 0xc8, 0x03, 0x38, 0xcd, 0xc1, 0x88, 0x0c, 0x94, 0xe3, 0xd2, + 0x4f, 0x36, 0xc7, 0x53, 0xb9, 0xac, 0xa2, 0x81, 0x13, 0x23, 0xfc, 0x29, 0x75, 0x0f, 0x5f, 0x09, + 0xeb, 0xd3, 0x70, 0xbb, 0x64, 0x43, 0x21, 0xe3, 0x92, 0xa4, 0x7f, 0x25, 0x1f, 0x25, 0x3a, 0x1f, + 0xcd, 0xee, 0xa0, 0x93, 0x01, 0x28, 0x96, 0x82, 0x50, 0x0e, 0x8c, 0x04, 0x7e, 0xec, 0x63, 0x38, + 0xd4, 0xe8, 0x3e, 0x8e, 0xf0, 0xa1, 0x4f, 0x99, 0xde, 0x49, 0x2f, 0x06, 0xa0, 0x76, 0x66, 0x78, + 0x1c, 0xb8, 0x3f, 0x79, 0xab, 0x6a, 0x3b, 0x03, 0x3c, 0x63, 0x06, 0x7c, 0xe7, 0xe0, 0xad, 0x1c, + 0x3d, 0x08, 0xcd, 0x54, 0xd6, 0x1d, 0xf5, 0x78, 0x22, 0x87, 0xbb, 0xd5, 0x16, 0xd2, 0x59, 0x76, + 0x58, 0xf4, 0xfc, 0xf1, 0x6a, 0xc5, 0x19, 0x44, 0x1f, 0x54, 0x77, 0x2b, 0x4a, 0xdb, 0xa8, 0x74, + 0xc5, 0x19, 0xf8, 0x1b, 0x26, 0x37, 0x3a, 0xe7, 0x7d, 0xee, 0xfc, 0x4b, 0x21, 0x2f, 0x1c, 0xc3, + 0xeb, 0x57, 0xa8, 0x7e, 0xf4, 0x30, 0xf4, 0xfc, 0x58, 0x7f, 0xe2, 0xe5, 0xbd, 0x52, 0xa5, 0xff, + 0xaa, 0x91, 0x99, 0x52, 0xe1, 0x85, 0x67, 0x87, 0x12, 0xcf, 0x2e, 0x2c, 0x48, 0xa6, 0x53, 0x88, + 0x36, 0xf0, 0x79, 0xd1, 0xb9, 0x38, 0x6f, 0xb5, 0x76, 0xa7, 0x68, 0x7f, 0xe5, 0x75, 0xbf, 0x7a, + 0xb6, 0x5f, 0xb2, 0x5f, 0xe8, 0x14, 0x5e, 0xfd, 0x7f, 0x24, 0x6e, 0xc1, 0x6b, 0x80, 0x1d, 0xca, + 0x69, 0x80, 0x76, 0x48, 0xdd, 0x8f, 0x83, 0xf9, 0x81, 0xe0, 0xf7, 0x3f, 0xc4, 0xef, 0xaf, 0x5f, + 0x9c, 0xb7, 0xe6, 0x4a, 0xc3, 0xf2, 0x5b, 0xb7, 0xca, 0x9f, 0xbb, 0xa7, 0x90, 0xa0, 0xf7, 0x9c, + 0x4f, 0xec, 0x0e, 0x25, 0xfa, 0xbc, 0x20, 0x8b, 0x16, 0x8c, 0xe0, 0x92, 0x29, 0x6d, 0x32, 0x2e, + 0xc5, 0x19, 0xd6, 0x37, 0x78, 0xfe, 0x14, 0x3d, 0x97, 0x5f, 0x9d, 0xb7, 0x1a, 0x5d, 0x84, 0xbe, + 0x9c, 0x66, 0xd0, 0xac, 0x61, 0x2f, 0x17, 0xe8, 0x1e, 0x69, 0x28, 0x38, 0x61, 0x36, 0x19, 0x40, + 0xc6, 0x59, 0x32, 0xe0, 0xaa, 0x0f, 0x26, 0xd8, 0x7e, 0x84, 0xb6, 0xd1, 0xab, 0xf3, 0xd6, 0xc2, + 0x97, 0x70, 0xd2, 0x45, 0xa2, 0x1d, 0x00, 0xf4, 0x5c, 0x50, 0x97, 0x44, 0xe9, 0xdf, 0xc9, 0x4d, + 0x0b, 0xc3, 0x02, 0x54, 0x02, 0x2c, 0xe1, 0xc9, 0x00, 0xa2, 0x8f, 0x57, 0xaf, 0x6e, 0xcc, 0x7d, + 0xb2, 0xb3, 0xf9, 0x23, 0xcf, 0xea, 0xcd, 0xcb, 0x1e, 0xcf, 0x9b, 0xdd, 0xd2, 0xa7, 0xed, 0x6d, + 0x76, 0x95, 0x33, 0xa3, 0xf0, 0x2e, 0x9c, 0x89, 0xc7, 0x75, 0x3b, 0xfd, 0x73, 0x69, 0x48, 0xe8, + 0x9b, 0x79, 0x74, 0x9e, 0x5c, 0x3d, 0x82, 0x11, 0x3e, 0xbc, 0xeb, 0xb1, 0xff, 0x93, 0xee, 0x92, + 0x77, 0xf0, 0x96, 0xc0, 0x57, 0xf5, 0xdc, 0x27, 0x5b, 0x3f, 0x3a, 0xbc, 0x37, 0x1d, 0xe3, 0x90, + 0xfd, 0xe9, 0x5b, 0x8f, 0x6a, 0x9f, 0xbf, 0x7d, 0x6d, 0x75, 0x7e, 0x6d, 0xfd, 0xdf, 0xb5, 0x4b, + 0xbf, 0xfc, 0x80, 0xdc, 0xc4, 0x32, 0xa4, 0xec, 0x18, 0x8c, 0xb7, 0x2c, 0x07, 0x51, 0x0f, 0xd1, + 0xaf, 0x43, 0x90, 0xde, 0x23, 0xf5, 0xa4, 0x30, 0x06, 0x94, 0x63, 0x93, 0x61, 0x5d, 0x8d, 0x6f, + 0x94, 0x41, 0xbc, 0xb3, 0xe8, 0x5d, 0x72, 0x5d, 0xa8, 0xc4, 0x80, 0xef, 0xb7, 0xf0, 0x7e, 0x8f, + 0x27, 0x01, 0xba, 0x42, 0xc8, 0xf8, 0xee, 0xb3, 0xe1, 0x75, 0x1e, 0x5f, 0xaf, 0xee, 0x3b, 0xbb, + 0xbd, 0xf5, 0xed, 0x7f, 0x9b, 0x57, 0xbe, 0xbd, 0x68, 0xd6, 0xbe, 0xbb, 0x68, 0xd6, 0xbe, 0xbf, + 0x68, 0xd6, 0xfe, 0x73, 0xd1, 0xac, 0xfd, 0xf3, 0x65, 0xf3, 0xca, 0x77, 0x2f, 0x9b, 0x57, 0xbe, + 0x7f, 0xd9, 0xbc, 0xf2, 0x4d, 0x7d, 0x66, 0xd2, 0x87, 0xef, 0xe2, 0xff, 0x36, 0xbf, 0xfc, 0x5f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xe5, 0xb2, 0x03, 0x41, 0x0d, 0x00, 0x00, } func (m *LocalOnlySessionData) Marshal() (dAtA []byte, err error) { @@ -326,6 +387,37 @@ func (m *LocalOnlySessionData) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.SequenceCache) > 0 { + keysForSequenceCache := make([]uint32, 0, len(m.SequenceCache)) + for k := range m.SequenceCache { + keysForSequenceCache = append(keysForSequenceCache, uint32(k)) + } + github_com_gogo_protobuf_sortkeys.Uint32s(keysForSequenceCache) + for iNdEx := len(keysForSequenceCache) - 1; iNdEx >= 0; iNdEx-- { + v := m.SequenceCache[uint32(keysForSequenceCache[iNdEx])] + baseI := i + if v != nil { + { + size, err := v.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(keysForSequenceCache[iNdEx])) + i-- + dAtA[i] = 0x8 + i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2 + i-- + dAtA[i] = 0xe2 + } + } if m.NewSchemaChangerMode != 0 { i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(m.NewSchemaChangerMode)) i-- @@ -737,6 +829,49 @@ func (m *LocalOnlySessionData) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SequenceCacheEntry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SequenceCacheEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SequenceCacheEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.NumValues != 0 { + i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(m.NumValues)) + i-- + dAtA[i] = 0x20 + } + if m.Increment != 0 { + i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(m.Increment)) + i-- + dAtA[i] = 0x18 + } + if m.CurrentValue != 0 { + i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(m.CurrentValue)) + i-- + dAtA[i] = 0x10 + } + if m.CachedVersion != 0 { + i = encodeVarintLocalOnlySessionData(dAtA, i, uint64(m.CachedVersion)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintLocalOnlySessionData(dAtA []byte, offset int, v uint64) int { offset -= sovLocalOnlySessionData(v) base := offset @@ -882,6 +1017,40 @@ func (m *LocalOnlySessionData) Size() (n int) { if m.NewSchemaChangerMode != 0 { n += 2 + sovLocalOnlySessionData(uint64(m.NewSchemaChangerMode)) } + if len(m.SequenceCache) > 0 { + for k, v := range m.SequenceCache { + _ = k + _ = v + l = 0 + if v != nil { + l = v.Size() + l += 1 + sovLocalOnlySessionData(uint64(l)) + } + mapEntrySize := 1 + sovLocalOnlySessionData(uint64(k)) + l + n += mapEntrySize + 2 + sovLocalOnlySessionData(uint64(mapEntrySize)) + } + } + return n +} + +func (m *SequenceCacheEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CachedVersion != 0 { + n += 1 + sovLocalOnlySessionData(uint64(m.CachedVersion)) + } + if m.CurrentValue != 0 { + n += 1 + sovLocalOnlySessionData(uint64(m.CurrentValue)) + } + if m.Increment != 0 { + n += 1 + sovLocalOnlySessionData(uint64(m.Increment)) + } + if m.NumValues != 0 { + n += 1 + sovLocalOnlySessionData(uint64(m.NumValues)) + } return n } @@ -1772,6 +1941,247 @@ func (m *LocalOnlySessionData) Unmarshal(dAtA []byte) error { break } } + case 44: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SequenceCache", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLocalOnlySessionData + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLocalOnlySessionData + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.SequenceCache == nil { + m.SequenceCache = make(SequenceCache) + } + var mapkey uint32 + var mapvalue *SequenceCacheEntry + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapkey |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthLocalOnlySessionData + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthLocalOnlySessionData + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &SequenceCacheEntry{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipLocalOnlySessionData(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLocalOnlySessionData + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.SequenceCache[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLocalOnlySessionData(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLocalOnlySessionData + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SequenceCacheEntry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SequenceCacheEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SequenceCacheEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CachedVersion", wireType) + } + m.CachedVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CachedVersion |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentValue", wireType) + } + m.CurrentValue = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentValue |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Increment", wireType) + } + m.Increment = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Increment |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumValues", wireType) + } + m.NumValues = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLocalOnlySessionData + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumValues |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipLocalOnlySessionData(dAtA[iNdEx:]) diff --git a/pkg/sql/sessiondatapb/local_only_session_data.proto b/pkg/sql/sessiondatapb/local_only_session_data.proto index 12334796c103..d2d3b97f7fe1 100644 --- a/pkg/sql/sessiondatapb/local_only_session_data.proto +++ b/pkg/sql/sessiondatapb/local_only_session_data.proto @@ -165,6 +165,9 @@ message LocalOnlySessionData { int64 serial_normalization_mode = 42 [(gogoproto.casttype)="SerialNormalizationMode"]; // NewSchemaChangerMode indicates whether to use the new schema changer. int64 new_schema_changer_mode = 43 [(gogoproto.casttype)="NewSchemaChangerMode"]; + // SequenceCache stores sequence values which have been cached using the + // CACHE sequence option. + map sequence_cache = 44 [(gogoproto.casttype)="SequenceCache"]; /////////////////////////////////////////////////////////////////////////// // WARNING: consider whether a session parameter you're adding needs to // @@ -172,3 +175,19 @@ message LocalOnlySessionData { // in the SessionData message instead. // /////////////////////////////////////////////////////////////////////////// } + +// SequenceCacheEntry is an entry in a SequenceCache. +message SequenceCacheEntry { + // CachedVersion stores the descpb.DescriptorVersion that cached values are associated with. + // The version is checked to determine if cache needs to be invalidated. The version is stored as + // a uint32 to prevent an import cycle with the descpb package. + uint32 cached_version = 1; + // CurrentValue stores the present value of the sequence to be given out. + int64 current_value = 2; + // Increment stores the amount to Increment the currentVal by each time the + // currentVal is used. This value corresponds to descpb.TableDescriptor_SequenceOpts.Increment. + int64 increment = 3; + // NumValues represents the number of values to cache. The cache is considered + // to be empty when NumValues is 0. + int64 num_values = 4; +} diff --git a/pkg/sql/sessiondata/sequence_cache.go b/pkg/sql/sessiondatapb/sequence_cache.go similarity index 60% rename from pkg/sql/sessiondata/sequence_cache.go rename to pkg/sql/sessiondatapb/sequence_cache.go index d3503b937b60..71bfddc966a9 100644 --- a/pkg/sql/sessiondata/sequence_cache.go +++ b/pkg/sql/sessiondatapb/sequence_cache.go @@ -8,7 +8,7 @@ // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. -package sessiondata +package sessiondatapb // SequenceCache stores sequence values that have already been created in KV // and are available to be given out as sequence numbers. Values for sequences @@ -20,22 +20,7 @@ package sessiondata // new descriptor versions may not monotonically increase. For example, the sequence schema // may be altered in a txn, so the cache sees a new version V and invalidates/repopulates itself. Then, // the txn may get rolled back, so the cache will see version V-1 and invalidate/repopulate itself again. -type SequenceCache map[uint32]*sequenceCacheEntry - -type sequenceCacheEntry struct { - // cachedVersion stores the descpb.DescriptorVersion that cached values are associated with. - // The version is checked to determine if cache needs to be invalidated. The version is stored as - // a uint32 to prevent an import cycle with the descpb package. - cachedVersion uint32 - // currentValue stores the present value of the sequence to be given out. - currentValue int64 - // increment stores the amount to increment the currentVal by each time the - // currentVal is used. This value corresponds to descpb.TableDescriptor_SequenceOpts.Increment. - increment int64 - // numValues represents the number of values to cache. The cache is considered - // to be empty when numValues is 0. - numValues int64 -} +type SequenceCache map[uint32]*SequenceCacheEntry // NextValue fetches the next value in the sequence cache. If the values in the cache have all been // given out or if the descriptor version has changed, then fetchNextValues() is used to repopulate the cache. @@ -44,14 +29,14 @@ func (sc SequenceCache) NextValue( ) (int64, error) { // Create entry for this sequence ID if there are no existing entries. if _, found := sc[seqID]; !found { - sc[seqID] = &sequenceCacheEntry{} + sc[seqID] = &SequenceCacheEntry{} } cacheEntry := sc[seqID] - if cacheEntry.numValues > 0 && cacheEntry.cachedVersion == clientVersion { - cacheEntry.currentValue += cacheEntry.increment - cacheEntry.numValues-- - return cacheEntry.currentValue - cacheEntry.increment, nil + if cacheEntry.NumValues > 0 && cacheEntry.CachedVersion == clientVersion { + cacheEntry.CurrentValue += cacheEntry.Increment + cacheEntry.NumValues-- + return cacheEntry.CurrentValue - cacheEntry.Increment, nil } currentValue, increment, numValues, err := fetchNextValues() @@ -61,9 +46,9 @@ func (sc SequenceCache) NextValue( // One value must be returned, and the rest of the values are stored. val := currentValue - cacheEntry.currentValue = currentValue + increment - cacheEntry.increment = increment - cacheEntry.numValues = numValues - 1 - cacheEntry.cachedVersion = clientVersion + cacheEntry.CurrentValue = currentValue + increment + cacheEntry.Increment = increment + cacheEntry.NumValues = numValues - 1 + cacheEntry.CachedVersion = clientVersion return val, nil } From 2a91d4ce45cec029c110889efb2c5b16e7af5158 Mon Sep 17 00:00:00 2001 From: Oliver Tan Date: Fri, 20 Aug 2021 08:48:30 +1000 Subject: [PATCH 2/3] builtins: implement session serialization and deserialization Release note (sql change): Implement the crdb_internal.serialize_session() and crdb_internal.deserialize_session(bytes) builtins, the former outputs the session settings in a string that can be deserialized into another session by the latter. --- docs/generated/sql/functions.md | 4 + pkg/sql/BUILD.bazel | 1 + pkg/sql/sem/builtins/BUILD.bazel | 1 + pkg/sql/sem/builtins/builtins.go | 90 +++++ pkg/sql/session_migration_test.go | 135 +++++++ pkg/sql/sessiondata/session_data.go | 7 + pkg/sql/sessiondatapb/BUILD.bazel | 1 + pkg/sql/sessiondatapb/session_migration.pb.go | 361 ++++++++++++++++++ pkg/sql/sessiondatapb/session_migration.proto | 24 ++ pkg/sql/testdata/session_migration/errors | 31 ++ pkg/sql/testdata/session_migration/sequence | 38 ++ .../session_migration/session_migration | 55 +++ 12 files changed, 748 insertions(+) create mode 100644 pkg/sql/session_migration_test.go create mode 100644 pkg/sql/sessiondatapb/session_migration.pb.go create mode 100644 pkg/sql/sessiondatapb/session_migration.proto create mode 100644 pkg/sql/testdata/session_migration/errors create mode 100644 pkg/sql/testdata/session_migration/sequence create mode 100644 pkg/sql/testdata/session_migration/session_migration diff --git a/docs/generated/sql/functions.md b/docs/generated/sql/functions.md index aac5ab83e788..ec8d6101f748 100644 --- a/docs/generated/sql/functions.md +++ b/docs/generated/sql/functions.md @@ -2801,6 +2801,8 @@ SELECT * FROM crdb_internal.check_consistency(true, ‘\x02’, ‘\x04’)

crdb_internal.create_join_token() → string

Creates a join token for use when adding a new node to a secure cluster.

+crdb_internal.deserialize_session(session: bytes) → bool

This function deserializes the serialized variables into the current session.

+
crdb_internal.encode_key(table_id: int, index_id: int, row_tuple: anyelement) → bytes

Generate the key for a row on a particular table and index.

crdb_internal.force_assertion_error(msg: string) → int

This function is used only by CockroachDB’s developers for testing purposes.

@@ -2864,6 +2866,8 @@ SELECT * FROM crdb_internal.check_consistency(true, ‘\x02’, ‘\x04’)

crdb_internal.round_decimal_values(val: decimal[], scale: int) → decimal[]

This function is used internally to round decimal array values during mutations.

+crdb_internal.serialize_session() → bytes

This function serializes the variables in the current session.

+
crdb_internal.set_trace_verbose(trace_id: int, verbosity: bool) → bool

Returns true if root span was found and verbosity was set, false otherwise.

crdb_internal.set_vmodule(vmodule_string: string) → int

Set the equivalent of the --vmodule flag on the gateway node processing this request; it affords control over the logging verbosity of different files. Example syntax: crdb_internal.set_vmodule('recordio=2,file=1,gfs*=3'). Reset with: crdb_internal.set_vmodule(''). Raising the verbosity can severely affect performance.

diff --git a/pkg/sql/BUILD.bazel b/pkg/sql/BUILD.bazel index c5eb99b5a6d8..c79c17e3f5d0 100644 --- a/pkg/sql/BUILD.bazel +++ b/pkg/sql/BUILD.bazel @@ -483,6 +483,7 @@ go_test( "schema_changer_test.go", "scrub_test.go", "sequence_test.go", + "session_migration_test.go", "set_zone_config_test.go", "show_create_all_tables_builtin_test.go", "show_fingerprints_test.go", diff --git a/pkg/sql/sem/builtins/BUILD.bazel b/pkg/sql/sem/builtins/BUILD.bazel index 86e14cda1d8f..1910643c6d00 100644 --- a/pkg/sql/sem/builtins/BUILD.bazel +++ b/pkg/sql/sem/builtins/BUILD.bazel @@ -78,6 +78,7 @@ go_library( "//pkg/util/json", "//pkg/util/log", "//pkg/util/mon", + "//pkg/util/protoutil", "//pkg/util/ring", "//pkg/util/syncutil", "//pkg/util/timeofday", diff --git a/pkg/sql/sem/builtins/builtins.go b/pkg/sql/sem/builtins/builtins.go index 66ea0f7841a9..549defa2ffa9 100644 --- a/pkg/sql/sem/builtins/builtins.go +++ b/pkg/sql/sem/builtins/builtins.go @@ -71,6 +71,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/util/ipaddr" "github.com/cockroachdb/cockroach/pkg/util/json" "github.com/cockroachdb/cockroach/pkg/util/log" + "github.com/cockroachdb/cockroach/pkg/util/protoutil" "github.com/cockroachdb/cockroach/pkg/util/timeofday" "github.com/cockroachdb/cockroach/pkg/util/timetz" "github.com/cockroachdb/cockroach/pkg/util/timeutil" @@ -5862,6 +5863,95 @@ table's zone configuration this will return NULL.`, Volatility: tree.VolatilityVolatile, }, ), + + "crdb_internal.serialize_session": makeBuiltin( + tree.FunctionProperties{ + Category: categorySystemInfo, + }, + tree.Overload{ + Types: tree.ArgTypes{}, + ReturnType: tree.FixedReturnType(types.Bytes), + Fn: func(evalCtx *tree.EvalContext, args tree.Datums) (tree.Datum, error) { + if !evalCtx.TxnImplicit { + return nil, pgerror.Newf( + pgcode.InvalidTransactionState, + "cannot serialize a session which is inside a transaction", + ) + } + + sd := evalCtx.SessionData + if sd == nil { + return nil, pgerror.Newf( + pgcode.InvalidTransactionState, + "no session is active", + ) + } + + if len(sd.DatabaseIDToTempSchemaID) > 0 { + return nil, pgerror.Newf( + pgcode.InvalidTransactionState, + "cannot serialize session with temporary schemas", + ) + } + + var m sessiondatapb.MigratableSession + m.SessionData = sd.SessionData + sessiondata.MarshalNonLocal(sd, &m.SessionData) + m.LocalOnlySessionData = sd.LocalOnlySessionData + + b, err := protoutil.Marshal(&m) + if err != nil { + return nil, err + } + return tree.NewDBytes(tree.DBytes(b)), nil + }, + Info: `This function serializes the variables in the current session.`, + Volatility: tree.VolatilityVolatile, + }, + ), + + "crdb_internal.deserialize_session": makeBuiltin( + tree.FunctionProperties{ + Category: categorySystemInfo, + }, + tree.Overload{ + Types: tree.ArgTypes{{"session", types.Bytes}}, + ReturnType: tree.FixedReturnType(types.Bool), + Fn: func(evalCtx *tree.EvalContext, args tree.Datums) (tree.Datum, error) { + if !evalCtx.TxnImplicit { + return nil, pgerror.Newf( + pgcode.InvalidTransactionState, + "cannot deserialize a session which is inside a transaction", + ) + } + + var m sessiondatapb.MigratableSession + if err := protoutil.Unmarshal([]byte(tree.MustBeDBytes(args[0])), &m); err != nil { + return nil, pgerror.WithCandidateCode( + errors.Wrapf(err, "error deserializing session"), + pgcode.InvalidParameterValue, + ) + } + sd, err := sessiondata.UnmarshalNonLocal(m.SessionData) + if err != nil { + return nil, err + } + sd.SessionData = m.SessionData + sd.LocalUnmigratableSessionData = evalCtx.SessionData.LocalUnmigratableSessionData + sd.LocalOnlySessionData = m.LocalOnlySessionData + if sd.SessionUser().Normalized() != evalCtx.SessionData.SessionUser().Normalized() { + return nil, pgerror.Newf( + pgcode.InsufficientPrivilege, + "can only serialize matching session users", + ) + } + *evalCtx.SessionData = *sd + return tree.MakeDBool(true), nil + }, + Info: `This function deserializes the serialized variables into the current session.`, + Volatility: tree.VolatilityVolatile, + }, + ), } var lengthImpls = func(incBitOverload bool) builtinDefinition { diff --git a/pkg/sql/session_migration_test.go b/pkg/sql/session_migration_test.go new file mode 100644 index 000000000000..b9eeee6644d1 --- /dev/null +++ b/pkg/sql/session_migration_test.go @@ -0,0 +1,135 @@ +// Copyright 2021 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package sql_test + +import ( + "context" + gosql "database/sql" + "fmt" + "strings" + "testing" + + "github.com/cockroachdb/cockroach/pkg/base" + "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" + "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" + "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" + "github.com/cockroachdb/cockroach/pkg/util/leaktest" + "github.com/cockroachdb/cockroach/pkg/util/log" + "github.com/cockroachdb/datadriven" + "github.com/stretchr/testify/require" +) + +// TestSessionMigration tests migrating a session as a data driven test. +// It supports the following directives: +// * reset: resets the connection. +// * exec: executes a SQL command +// * query: executes a SQL command and returns the output +// * dump_vars: dumps variables into a variable called with the given input. +// * compare_vars: compares two dumped variables. +func TestSessionMigration(t *testing.T) { + defer leaktest.AfterTest(t)() + defer log.Scope(t).Close(t) + + ctx := context.Background() + datadriven.Walk(t, "testdata/session_migration", func(t *testing.T, path string) { + tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{}) + defer tc.Stopper().Stop(ctx) + + openConnFunc := func() *gosql.DB { + return serverutils.OpenDBConn( + t, + tc.Server(0).ServingSQLAddr(), + "defaultdb", /* database */ + false, /* insecure */ + tc.Server(0).Stopper(), + ) + } + dbConn := openConnFunc() + defer func() { + _ = dbConn.Close() + }() + + vars := make(map[string]string) + datadriven.RunTest(t, path, func(t *testing.T, d *datadriven.TestData) string { + getQuery := func() string { + q := d.Input + for k, v := range vars { + q = strings.ReplaceAll(q, k, v) + } + return q + } + switch d.Cmd { + case "reset": + require.NoError(t, dbConn.Close()) + dbConn = openConnFunc() + return "" + case "exec": + _, err := dbConn.Exec(getQuery()) + if err != nil { + return err.Error() + } + return "" + case "dump_vars": + require.NotEmpty(t, d.Input, "expected table name") + _, err := dbConn.Exec(fmt.Sprintf("CREATE TABLE %s AS SELECT * FROM [SHOW ALL]", d.Input)) + require.NoError(t, err) + return "" + case "compare_vars": + tables := strings.Split(d.Input, "\n") + require.Len(t, tables, 2, "require 2 tables to compare against") + + q := `SELECT dump.variable, dump.value, dump2.variable, dump2.value +FROM dump +FULL OUTER JOIN dump2 +ON ( dump.variable = dump2.variable ) +WHERE dump.variable IS NULL OR dump2.variable IS NULL OR dump.variable != dump2.variable` + for _, repl := range []struct { + from string + to string + }{ + {"dump2", tables[1]}, + {"dump", tables[0]}, + } { + q = strings.ReplaceAll(q, repl.from, repl.to) + } + rows, err := dbConn.Query(q) + require.NoError(t, err) + ret, err := sqlutils.RowsToDataDrivenOutput(rows) + require.NoError(t, err) + return ret + case "query": + q := d.Input + for k, v := range vars { + q = strings.ReplaceAll(q, k, v) + } + rows, err := dbConn.Query(getQuery()) + if err != nil { + return err.Error() + } + ret, err := sqlutils.RowsToDataDrivenOutput(rows) + require.NoError(t, err) + return ret + case "let": + row := dbConn.QueryRow(getQuery()) + var v string + require.NoError(t, row.Err()) + require.NoError(t, row.Scan(&v)) + require.Len(t, d.CmdArgs, 1, "only one argument permitted for let") + for _, arg := range d.CmdArgs { + vars[arg.Key] = v + } + return "" + } + t.Fatalf("unknown command: %s", d.Cmd) + return "unexpected" + }) + }) +} diff --git a/pkg/sql/sessiondata/session_data.go b/pkg/sql/sessiondata/session_data.go index 5eefb1da406d..80f1d90883ec 100644 --- a/pkg/sql/sessiondata/session_data.go +++ b/pkg/sql/sessiondata/session_data.go @@ -14,6 +14,7 @@ import ( "net" "time" + "github.com/cockroachdb/cockroach/pkg/security" "github.com/cockroachdb/cockroach/pkg/sql/sessiondatapb" "github.com/cockroachdb/cockroach/pkg/util/duration" "github.com/cockroachdb/cockroach/pkg/util/timeutil" @@ -125,6 +126,12 @@ func (s *SessionData) GetDateStyle() pgdate.DateStyle { return s.DataConversionConfig.DateStyle } +// SessionUser retrieves the session_user. +// This currently returns current_user, as session_user is not implemented. +func (s *SessionData) SessionUser() security.SQLUsername { + return s.User() +} + // LocalUnmigratableSessionData contains session parameters that cannot // be propagated to remote nodes and cannot be migrated to another // session. diff --git a/pkg/sql/sessiondatapb/BUILD.bazel b/pkg/sql/sessiondatapb/BUILD.bazel index 84bf5fc888ab..9cde792673dc 100644 --- a/pkg/sql/sessiondatapb/BUILD.bazel +++ b/pkg/sql/sessiondatapb/BUILD.bazel @@ -20,6 +20,7 @@ proto_library( srcs = [ "local_only_session_data.proto", "session_data.proto", + "session_migration.proto", ], strip_import_prefix = "/pkg", visibility = ["//visibility:public"], diff --git a/pkg/sql/sessiondatapb/session_migration.pb.go b/pkg/sql/sessiondatapb/session_migration.pb.go new file mode 100644 index 000000000000..52819c005e13 --- /dev/null +++ b/pkg/sql/sessiondatapb/session_migration.pb.go @@ -0,0 +1,361 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: sql/sessiondatapb/session_migration.proto + +package sessiondatapb + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MigratableSession represents a serialization of a session that can be +// migrated between SQL sessions. +type MigratableSession struct { + SessionData SessionData `protobuf:"bytes,1,opt,name=session_data,json=sessionData,proto3" json:"session_data"` + LocalOnlySessionData LocalOnlySessionData `protobuf:"bytes,2,opt,name=local_only_session_data,json=localOnlySessionData,proto3" json:"local_only_session_data"` +} + +func (m *MigratableSession) Reset() { *m = MigratableSession{} } +func (m *MigratableSession) String() string { return proto.CompactTextString(m) } +func (*MigratableSession) ProtoMessage() {} +func (*MigratableSession) Descriptor() ([]byte, []int) { + return fileDescriptor_e44b77d7af899ce0, []int{0} +} +func (m *MigratableSession) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MigratableSession) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *MigratableSession) XXX_Merge(src proto.Message) { + xxx_messageInfo_MigratableSession.Merge(m, src) +} +func (m *MigratableSession) XXX_Size() int { + return m.Size() +} +func (m *MigratableSession) XXX_DiscardUnknown() { + xxx_messageInfo_MigratableSession.DiscardUnknown(m) +} + +var xxx_messageInfo_MigratableSession proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MigratableSession)(nil), "cockroach.sql.sessiondatapb.MigratableSession") +} + +func init() { + proto.RegisterFile("sql/sessiondatapb/session_migration.proto", fileDescriptor_e44b77d7af899ce0) +} + +var fileDescriptor_e44b77d7af899ce0 = []byte{ + // 239 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2c, 0x2e, 0xcc, 0xd1, + 0x2f, 0x4e, 0x2d, 0x2e, 0xce, 0xcc, 0xcf, 0x4b, 0x49, 0x2c, 0x49, 0x2c, 0x48, 0x82, 0xf1, 0xe2, + 0x73, 0x33, 0xd3, 0x8b, 0x12, 0x4b, 0x32, 0xf3, 0xf3, 0xf4, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, + 0xa4, 0x93, 0xf3, 0x93, 0xb3, 0x8b, 0xf2, 0x13, 0x93, 0x33, 0xf4, 0x8a, 0x0b, 0x73, 0xf4, 0x50, + 0x34, 0x49, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0xd5, 0xe9, 0x83, 0x58, 0x10, 0x2d, 0x52, 0x2a, + 0xb8, 0x4d, 0x07, 0x71, 0xa1, 0xaa, 0xf4, 0x31, 0x55, 0xe5, 0xe4, 0x27, 0x27, 0xe6, 0xc4, 0xe7, + 0xe7, 0xe5, 0x54, 0xc6, 0x63, 0x6a, 0x50, 0xba, 0xc6, 0xc8, 0x25, 0xe8, 0x0b, 0x76, 0x5d, 0x62, + 0x52, 0x4e, 0x6a, 0x30, 0x44, 0x81, 0x50, 0x20, 0x17, 0x0f, 0xb2, 0x5a, 0x09, 0x46, 0x05, 0x46, + 0x0d, 0x6e, 0x23, 0x0d, 0x3d, 0x3c, 0xce, 0xd6, 0x83, 0xea, 0x75, 0x49, 0x2c, 0x49, 0x74, 0x62, + 0x39, 0x71, 0x4f, 0x9e, 0x21, 0x88, 0xbb, 0x18, 0x21, 0x24, 0x94, 0xc7, 0x25, 0x8e, 0xc3, 0x25, + 0x12, 0x4c, 0x60, 0xd3, 0x0d, 0xf1, 0x9a, 0xee, 0x03, 0xd2, 0xeb, 0x9f, 0x97, 0x53, 0x89, 0x69, + 0x8d, 0x48, 0x0e, 0x36, 0x39, 0xfd, 0x13, 0x0f, 0xe5, 0x18, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, + 0x48, 0x8e, 0xf1, 0xc6, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, + 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0x5e, 0x14, 0x1b, 0x92, 0xd8, 0xc0, 0x01, + 0x62, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x9a, 0xec, 0xc3, 0xcb, 0xc7, 0x01, 0x00, 0x00, +} + +func (m *MigratableSession) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MigratableSession) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MigratableSession) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.LocalOnlySessionData.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSessionMigration(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.SessionData.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSessionMigration(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintSessionMigration(dAtA []byte, offset int, v uint64) int { + offset -= sovSessionMigration(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MigratableSession) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.SessionData.Size() + n += 1 + l + sovSessionMigration(uint64(l)) + l = m.LocalOnlySessionData.Size() + n += 1 + l + sovSessionMigration(uint64(l)) + return n +} + +func sovSessionMigration(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozSessionMigration(x uint64) (n int) { + return sovSessionMigration(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MigratableSession) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSessionMigration + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MigratableSession: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MigratableSession: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SessionData", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSessionMigration + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSessionMigration + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSessionMigration + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.SessionData.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LocalOnlySessionData", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSessionMigration + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSessionMigration + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSessionMigration + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LocalOnlySessionData.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSessionMigration(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSessionMigration + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSessionMigration(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSessionMigration + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSessionMigration + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSessionMigration + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthSessionMigration + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSessionMigration + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthSessionMigration + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthSessionMigration = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSessionMigration = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSessionMigration = fmt.Errorf("proto: unexpected end of group") +) diff --git a/pkg/sql/sessiondatapb/session_migration.proto b/pkg/sql/sessiondatapb/session_migration.proto new file mode 100644 index 000000000000..df33af03edf2 --- /dev/null +++ b/pkg/sql/sessiondatapb/session_migration.proto @@ -0,0 +1,24 @@ +// Copyright 2021 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +syntax = "proto3"; +package cockroach.sql.sessiondatapb; +option go_package = "sessiondatapb"; + +import "gogoproto/gogo.proto"; +import "sql/sessiondatapb/session_data.proto"; +import "sql/sessiondatapb/local_only_session_data.proto"; + +// MigratableSession represents a serialization of a session that can be +// migrated between SQL sessions. +message MigratableSession { + cockroach.sql.sessiondatapb.SessionData session_data = 1 [(gogoproto.nullable)=false]; + cockroach.sql.sessiondatapb.LocalOnlySessionData local_only_session_data = 2 [(gogoproto.nullable)=false]; +} diff --git a/pkg/sql/testdata/session_migration/errors b/pkg/sql/testdata/session_migration/errors new file mode 100644 index 000000000000..22d9a520f79a --- /dev/null +++ b/pkg/sql/testdata/session_migration/errors @@ -0,0 +1,31 @@ +# This file contains error checks for session migration. + +exec +SELECT crdb_internal.deserialize_session('invalid proto') +---- +pq: crdb_internal.deserialize_session(): error deserializing session: unexpected EOF + +exec +SET experimental_enable_temp_tables = true; +CREATE TEMP TABLE temp_tbl() +---- + +query +SELECT crdb_internal.serialize_session() +---- +pq: crdb_internal.serialize_session(): cannot serialize session with temporary schemas + +reset +---- + +exec +BEGIN +---- + +query +SELECT crdb_internal.serialize_session() +---- +pq: crdb_internal.serialize_session(): cannot serialize a session which is inside a transaction + +reset +---- diff --git a/pkg/sql/testdata/session_migration/sequence b/pkg/sql/testdata/session_migration/sequence new file mode 100644 index 000000000000..129d6fb274e7 --- /dev/null +++ b/pkg/sql/testdata/session_migration/sequence @@ -0,0 +1,38 @@ +exec +SET serial_normalization = sql_sequence_cached; +CREATE TABLE serial ( + cached SERIAL +); +INSERT INTO serial (cached) VALUES (DEFAULT) +---- + +query +SELECT pg_get_serial_sequence('serial', 'cached') +---- +public.serial_cached_seq + +query +SELECT * FROM serial ORDER BY cached +---- +1 + +let $x +SELECT encode(crdb_internal.serialize_session(), 'hex') +---- + +reset +---- + +exec +SELECT crdb_internal.deserialize_session(decode('$x', 'hex')) +---- + +exec +INSERT INTO serial (cached) VALUES (DEFAULT) +---- + +query +SELECT * FROM serial ORDER BY cached +---- +1 +2 diff --git a/pkg/sql/testdata/session_migration/session_migration b/pkg/sql/testdata/session_migration/session_migration new file mode 100644 index 000000000000..a4de1f5423ec --- /dev/null +++ b/pkg/sql/testdata/session_migration/session_migration @@ -0,0 +1,55 @@ +# This file contains basic tests for session_migration. + +exec +CREATE DATABASE d; USE d +---- + +exec +SET extra_float_digits = -1; +SET enable_zigzag_join = false; +SET search_path = public +---- + +let $x +SELECT encode(crdb_internal.serialize_session(), 'hex') +---- + +dump_vars +old_state +---- + +reset +---- + +query +SHOW database +---- +defaultdb + +exec +SELECT crdb_internal.deserialize_session( decode('$x', 'hex') ) +---- + +query +SHOW database +---- +d + +dump_vars +new_state +---- + +compare_vars +old_state +new_state +---- + +exec +SELECT crdb_internal.deserialize_session( + decode( + '0a4a0a0964656661756c74646212102420636f636b726f6163682064656d6f1a04757365722204100222002802380842035554434a0524757365724a067075626c69635a0060808080207a00122b10904e3002380840026001680170017801880101d80101e00101f00101f80101900201b002808001c80201', + 'hex' + ) +) +---- +pq: crdb_internal.deserialize_session(): can only serialize matching session users From fcdb3105e96b7949f2555ff28d7df7077afc2496 Mon Sep 17 00:00:00 2001 From: Oliver Tan Date: Fri, 20 Aug 2021 09:11:11 +1000 Subject: [PATCH 3/3] builtins: prevent serializing prepared statements Release note: None --- pkg/sql/conn_executor.go | 49 +++++++++++-------- pkg/sql/faketreeeval/evalctx.go | 11 +++++ pkg/sql/sem/builtins/builtins.go | 7 +++ pkg/sql/sem/tree/eval.go | 8 +++ .../session_migration/session_migration | 17 +++++++ 5 files changed, 71 insertions(+), 21 deletions(-) diff --git a/pkg/sql/conn_executor.go b/pkg/sql/conn_executor.go index ef5511e52d37..8a0d4e04e9f5 100644 --- a/pkg/sql/conn_executor.go +++ b/pkg/sql/conn_executor.go @@ -1372,6 +1372,12 @@ type prepStmtNamespace struct { portals map[string]PreparedPortal } +// HasPrepared returns true if there are prepared statements or portals +// in the session. +func (ns prepStmtNamespace) HasPrepared() bool { + return len(ns.prepStmts) > 0 || len(ns.portals) > 0 +} + func (ns prepStmtNamespace) String() string { var sb strings.Builder sb.WriteString("Prep stmts: ") @@ -2309,27 +2315,28 @@ func (ex *connExecutor) initEvalCtx(ctx context.Context, evalCtx *extendedEvalCo *evalCtx = extendedEvalContext{ EvalContext: tree.EvalContext{ - Planner: p, - PrivilegedAccessor: p, - SessionAccessor: p, - ClientNoticeSender: p, - Sequence: p, - Tenant: p, - JoinTokenCreator: p, - SessionData: ex.sessionData, - Settings: ex.server.cfg.Settings, - TestingKnobs: ex.server.cfg.EvalContextTestingKnobs, - ClusterID: ex.server.cfg.ClusterID(), - ClusterName: ex.server.cfg.RPCContext.ClusterName(), - NodeID: ex.server.cfg.NodeID, - Codec: ex.server.cfg.Codec, - Locality: ex.server.cfg.Locality, - ReCache: ex.server.reCache, - InternalExecutor: &ie, - DB: ex.server.cfg.DB, - SQLLivenessReader: ex.server.cfg.SQLLivenessReader, - SQLStatsController: ex.server.sqlStatsController, - CompactEngineSpan: ex.server.cfg.CompactEngineSpanFunc, + Planner: p, + PrivilegedAccessor: p, + SessionAccessor: p, + ClientNoticeSender: p, + Sequence: p, + Tenant: p, + JoinTokenCreator: p, + PreparedStatementState: &ex.extraTxnState.prepStmtsNamespace, + SessionData: ex.sessionData, + Settings: ex.server.cfg.Settings, + TestingKnobs: ex.server.cfg.EvalContextTestingKnobs, + ClusterID: ex.server.cfg.ClusterID(), + ClusterName: ex.server.cfg.RPCContext.ClusterName(), + NodeID: ex.server.cfg.NodeID, + Codec: ex.server.cfg.Codec, + Locality: ex.server.cfg.Locality, + ReCache: ex.server.reCache, + InternalExecutor: &ie, + DB: ex.server.cfg.DB, + SQLLivenessReader: ex.server.cfg.SQLLivenessReader, + SQLStatsController: ex.server.sqlStatsController, + CompactEngineSpan: ex.server.cfg.CompactEngineSpanFunc, }, SessionMutator: ex.dataMutator, VirtualSchemas: ex.server.cfg.VirtualSchemas, diff --git a/pkg/sql/faketreeeval/evalctx.go b/pkg/sql/faketreeeval/evalctx.go index 40e7678d2a68..d82db085a2b8 100644 --- a/pkg/sql/faketreeeval/evalctx.go +++ b/pkg/sql/faketreeeval/evalctx.go @@ -433,3 +433,14 @@ func (c *DummyTenantOperator) UpdateTenantResourceLimits( ) error { return errors.WithStack(errEvalTenant) } + +// DummyPreparedStatementState implements the tree.PreparedStatementState +// interface. +type DummyPreparedStatementState struct{} + +var _ tree.PreparedStatementState = (*DummyPreparedStatementState)(nil) + +// HasPrepared is part of the tree.PreparedStatementState interface. +func (ps *DummyPreparedStatementState) HasPrepared() bool { + return false +} diff --git a/pkg/sql/sem/builtins/builtins.go b/pkg/sql/sem/builtins/builtins.go index 549defa2ffa9..374dd1a1fd23 100644 --- a/pkg/sql/sem/builtins/builtins.go +++ b/pkg/sql/sem/builtins/builtins.go @@ -5879,6 +5879,13 @@ table's zone configuration this will return NULL.`, ) } + if evalCtx.PreparedStatementState.HasPrepared() { + return nil, pgerror.Newf( + pgcode.InvalidTransactionState, + "cannot serialize a session which has portals or prepared statements", + ) + } + sd := evalCtx.SessionData if sd == nil { return nil, pgerror.Newf( diff --git a/pkg/sql/sem/tree/eval.go b/pkg/sql/sem/tree/eval.go index 28db1940d0f2..a6cd988ee208 100644 --- a/pkg/sql/sem/tree/eval.go +++ b/pkg/sql/sem/tree/eval.go @@ -3258,6 +3258,12 @@ type EvalSessionAccessor interface { HasRoleOption(ctx context.Context, roleOption roleoption.Option) (bool, error) } +// PreparedStatementState is a limited interface that exposes metadata about +// prepared statements. +type PreparedStatementState interface { + HasPrepared() bool +} + // ClientNoticeSender is a limited interface to send notices to the // client. // @@ -3531,6 +3537,8 @@ type EvalContext struct { JoinTokenCreator JoinTokenCreator + PreparedStatementState PreparedStatementState + // The transaction in which the statement is executing. Txn *kv.Txn // A handle to the database. diff --git a/pkg/sql/testdata/session_migration/session_migration b/pkg/sql/testdata/session_migration/session_migration index a4de1f5423ec..1e88558bed05 100644 --- a/pkg/sql/testdata/session_migration/session_migration +++ b/pkg/sql/testdata/session_migration/session_migration @@ -44,6 +44,10 @@ old_state new_state ---- +reset +---- + +# We cannot deserialize a different session_user. exec SELECT crdb_internal.deserialize_session( decode( @@ -53,3 +57,16 @@ SELECT crdb_internal.deserialize_session( ) ---- pq: crdb_internal.deserialize_session(): can only serialize matching session users + +reset +---- + +# We cannot serialized prepared statements +exec +PREPARE stmt AS SELECT 1 +---- + +exec +SELECT crdb_internal.serialize_session() +---- +pq: crdb_internal.serialize_session(): cannot serialize a session which has portals or prepared statements